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/llms.txt ADDED
@@ -0,0 +1,52 @@
1
+ # RoomKit
2
+
3
+ > RoomKit is a pure async Python library for building multi-channel conversation systems.
4
+ > It provides room-based abstractions for managing conversations across SMS, Email, WebSocket,
5
+ > AI, and other channels with pluggable storage, identity resolution, hooks, and realtime events.
6
+ > Python 3.12+, Pydantic 2.x, fully typed, zero required dependencies beyond Pydantic.
7
+
8
+ RoomKit follows a pluggable architecture pattern where core abstractions (ConversationStore,
9
+ RoomLockManager, RealtimeBackend, IdentityResolver) have in-memory defaults but can be replaced
10
+ with distributed implementations (Redis, PostgreSQL, etc.) for production deployments.
11
+
12
+ ## Getting Started
13
+
14
+ - [Features Overview](docs/features.md): Core features, channel support matrix, hooks, AI integration, resilience, identity resolution, and usage workflows
15
+ - [Architecture](docs/architecture.md): System design, component relationships, and extension points
16
+
17
+ ## Core API
18
+
19
+ - [RoomKit](docs/api/roomkit.md): Central orchestrator class - room lifecycle, channel management, hooks, inbound processing
20
+ - [Hooks](docs/api/hooks.md): HookEngine, HookRegistration - event interception at BEFORE_BROADCAST, AFTER_BROADCAST, lifecycle triggers
21
+ - [Routing](docs/api/routing.md): InboundRoomRouter - strategy for routing inbound messages to rooms
22
+ - [Store](docs/api/store.md): ConversationStore ABC and InMemoryStore - room, event, participant, task persistence
23
+ - [Realtime](docs/api/realtime.md): RealtimeBackend for ephemeral events - typing indicators, presence, read receipts. Key methods: `kit.publish_typing(room_id, user_id, is_typing=True)`, `kit.publish_presence(room_id, user_id, status)`, `kit.publish_read_receipt(room_id, user_id, event_id)`, `kit.subscribe_room(room_id, callback) -> subscription_id`, `kit.unsubscribe_room(subscription_id)`. EphemeralEventType enum: TYPING_START, TYPING_STOP, PRESENCE_ONLINE, PRESENCE_AWAY, PRESENCE_OFFLINE, READ_RECEIPT, CUSTOM
24
+
25
+ ## Channels
26
+
27
+ - [Channel ABC](docs/api/channel.md): Base class for all channels - handle_inbound, deliver, on_event, capabilities
28
+ - [Built-in Channels](docs/api/channels.md): SMSChannel, EmailChannel, AIChannel, WebSocketChannel, MessengerChannel, HTTPChannel, WhatsAppChannel
29
+
30
+ ## Models
31
+
32
+ - [Room & Timers](docs/api/room.md): Room model with status lifecycle (ACTIVE, PAUSED, CLOSED, ARCHIVED) and timer configuration
33
+ - [Events & Content](docs/api/events.md): RoomEvent, TextContent, MediaContent, RichContent, CompositeContent, TemplateContent, LocationContent
34
+ - [Identity](docs/api/identity.md): Identity, IdentityResult, IdentityHookResult, Participant - identification pipeline
35
+ - [Delivery](docs/api/delivery.md): InboundMessage, InboundResult, DeliveryResult, ProviderResult
36
+ - [Channel Models](docs/api/channel-models.md): ChannelBinding, ChannelCapabilities, ChannelOutput, RateLimit, RetryPolicy
37
+ - [Hook Models](docs/api/hook-models.md): HookResult, InjectedEvent, Task, Observation
38
+
39
+ ## Providers
40
+
41
+ - [AI Providers](docs/api/providers-ai.md): AIProvider ABC, AnthropicAIProvider, OpenAIAIProvider, GeminiAIProvider, MockAIProvider - context building, vision support
42
+ - [SMS Providers](docs/api/providers-sms.md): SMSProvider ABC, TwilioSMSProvider, TelnyxSMSProvider, SinchSMSProvider, VoiceMeUpSMSProvider - webhook parsing, signature verification, MMS support
43
+ - [Email Providers](docs/api/providers-email.md): EmailProvider ABC, ElasticEmailProvider
44
+ - [HTTP Providers](docs/api/providers-http.md): HTTPProvider ABC, WebhookHTTPProvider - generic webhook integration
45
+ - [Messenger Providers](docs/api/providers-messenger.md): MessengerProvider ABC, FacebookMessengerProvider
46
+
47
+ ## Optional
48
+
49
+ - [Enums](docs/api/enums.md): ChannelType, EventType, EventStatus, RoomStatus, HookTrigger, HookExecution, IdentificationStatus, ParticipantRole
50
+ - [Technical Details](docs/technical.md): Implementation details and internal architecture
51
+ - [RFC](docs/roomkit-rfc.md): Original design document and rationale
52
+ - [CPaaS Comparison](docs/cpaas-comparison.md): Comparison with other communication platforms
@@ -0,0 +1,104 @@
1
+ """RoomKit data models."""
2
+
3
+ from roomkit.models.channel import (
4
+ ChannelBinding,
5
+ ChannelCapabilities,
6
+ ChannelOutput,
7
+ RateLimit,
8
+ )
9
+ from roomkit.models.context import RoomContext
10
+ from roomkit.models.delivery import (
11
+ DeliveryResult,
12
+ InboundMessage,
13
+ InboundResult,
14
+ ProviderResult,
15
+ )
16
+ from roomkit.models.enums import (
17
+ Access,
18
+ ChannelCategory,
19
+ ChannelDirection,
20
+ ChannelMediaType,
21
+ ChannelType,
22
+ DeliveryMode,
23
+ EventStatus,
24
+ EventType,
25
+ HookExecution,
26
+ HookTrigger,
27
+ IdentificationStatus,
28
+ ParticipantRole,
29
+ ParticipantStatus,
30
+ RoomStatus,
31
+ TaskStatus,
32
+ )
33
+ from roomkit.models.event import (
34
+ AudioContent,
35
+ ChannelData,
36
+ CompositeContent,
37
+ EventContent,
38
+ EventSource,
39
+ LocationContent,
40
+ MediaContent,
41
+ RichContent,
42
+ RoomEvent,
43
+ SystemContent,
44
+ TemplateContent,
45
+ TextContent,
46
+ VideoContent,
47
+ )
48
+ from roomkit.models.framework_event import FrameworkEvent
49
+ from roomkit.models.hook import HookResult, InjectedEvent
50
+ from roomkit.models.identity import Identity, IdentityHookResult, IdentityResult
51
+ from roomkit.models.participant import Participant
52
+ from roomkit.models.room import Room, RoomTimers
53
+ from roomkit.models.task import Observation, Task
54
+
55
+ __all__ = [
56
+ "Access",
57
+ "AudioContent",
58
+ "ChannelBinding",
59
+ "ChannelCapabilities",
60
+ "ChannelCategory",
61
+ "ChannelData",
62
+ "ChannelDirection",
63
+ "ChannelMediaType",
64
+ "ChannelOutput",
65
+ "ChannelType",
66
+ "CompositeContent",
67
+ "DeliveryMode",
68
+ "DeliveryResult",
69
+ "EventContent",
70
+ "EventSource",
71
+ "EventStatus",
72
+ "EventType",
73
+ "FrameworkEvent",
74
+ "HookExecution",
75
+ "HookResult",
76
+ "HookTrigger",
77
+ "Identity",
78
+ "IdentificationStatus",
79
+ "IdentityHookResult",
80
+ "IdentityResult",
81
+ "InboundMessage",
82
+ "InboundResult",
83
+ "InjectedEvent",
84
+ "LocationContent",
85
+ "MediaContent",
86
+ "Observation",
87
+ "Participant",
88
+ "ParticipantRole",
89
+ "ParticipantStatus",
90
+ "ProviderResult",
91
+ "RateLimit",
92
+ "RichContent",
93
+ "Room",
94
+ "RoomContext",
95
+ "RoomEvent",
96
+ "RoomStatus",
97
+ "RoomTimers",
98
+ "SystemContent",
99
+ "Task",
100
+ "TaskStatus",
101
+ "TemplateContent",
102
+ "TextContent",
103
+ "VideoContent",
104
+ ]
@@ -0,0 +1,99 @@
1
+ """Channel-related data models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import UTC, datetime
6
+ from typing import Any
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+ from roomkit.models.enums import (
11
+ Access,
12
+ ChannelCategory,
13
+ ChannelDirection,
14
+ ChannelMediaType,
15
+ ChannelType,
16
+ DeliveryMode,
17
+ )
18
+ from roomkit.models.event import RoomEvent
19
+ from roomkit.models.task import Observation, Task
20
+
21
+
22
+ class RateLimit(BaseModel):
23
+ """Rate limiting configuration for a channel."""
24
+
25
+ max_per_second: float | None = Field(default=None, gt=0.0)
26
+ max_per_minute: float | None = Field(default=None, gt=0.0)
27
+ max_per_hour: float | None = Field(default=None, gt=0.0)
28
+
29
+
30
+ class RetryPolicy(BaseModel):
31
+ """Configures retry behaviour for channel delivery."""
32
+
33
+ max_retries: int = Field(default=3, ge=0)
34
+ base_delay_seconds: float = Field(default=1.0, gt=0.0)
35
+ max_delay_seconds: float = Field(default=60.0, gt=0.0)
36
+ exponential_base: float = Field(default=2.0, gt=0.0)
37
+
38
+
39
+ class ChannelCapabilities(BaseModel):
40
+ """What a channel can do."""
41
+
42
+ media_types: list[ChannelMediaType] = Field(default_factory=lambda: [ChannelMediaType.TEXT])
43
+ max_length: int | None = Field(default=None, gt=0)
44
+ supports_threading: bool = False
45
+ supports_reactions: bool = False
46
+ supports_read_receipts: bool = False
47
+ supports_typing: bool = False
48
+ supports_templates: bool = False
49
+ supports_rich_text: bool = False
50
+ supports_buttons: bool = False
51
+ max_buttons: int | None = Field(default=None, gt=0)
52
+ supports_cards: bool = False
53
+ supports_quick_replies: bool = False
54
+ supports_media: bool = False
55
+ supported_media_types: list[str] = Field(default_factory=list)
56
+ max_media_size_bytes: int | None = Field(default=None, gt=0)
57
+ supports_audio: bool = False
58
+ max_audio_duration_seconds: int | None = Field(default=None, gt=0)
59
+ supported_audio_formats: list[str] = Field(default_factory=list)
60
+ supports_video: bool = False
61
+ max_video_duration_seconds: int | None = Field(default=None, gt=0)
62
+ supported_video_formats: list[str] = Field(default_factory=list)
63
+ delivery_mode: DeliveryMode = DeliveryMode.BROADCAST
64
+ custom: dict[str, Any] = Field(default_factory=dict)
65
+
66
+
67
+ class ChannelBinding(BaseModel):
68
+ """A channel's attachment to a room."""
69
+
70
+ channel_id: str
71
+ room_id: str
72
+ channel_type: ChannelType
73
+ category: ChannelCategory = ChannelCategory.TRANSPORT
74
+ direction: ChannelDirection = ChannelDirection.BIDIRECTIONAL
75
+ access: Access = Access.READ_WRITE
76
+ muted: bool = False
77
+ visibility: str = "all"
78
+ participant_id: str | None = None
79
+ last_read_index: int | None = Field(default=None, ge=0)
80
+ attached_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
81
+ capabilities: ChannelCapabilities = Field(default_factory=ChannelCapabilities)
82
+ rate_limit: RateLimit | None = None
83
+ retry_policy: RetryPolicy | None = None
84
+ metadata: dict[str, Any] = Field(default_factory=dict)
85
+
86
+
87
+ class ChannelOutput(BaseModel):
88
+ """Output produced by a channel after receiving an event."""
89
+
90
+ responded: bool = False
91
+ response_events: list[RoomEvent] = Field(default_factory=list)
92
+ tasks: list[Task] = Field(default_factory=list)
93
+ observations: list[Observation] = Field(default_factory=list)
94
+ metadata_updates: dict[str, Any] = Field(default_factory=dict)
95
+
96
+ @classmethod
97
+ def empty(cls) -> ChannelOutput:
98
+ """Create an empty output with no responses or side effects."""
99
+ return cls()
@@ -0,0 +1,35 @@
1
+ """Room context model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from roomkit.models.channel import ChannelBinding
8
+ from roomkit.models.enums import ChannelType
9
+ from roomkit.models.event import RoomEvent
10
+ from roomkit.models.participant import Participant
11
+ from roomkit.models.room import Room
12
+
13
+
14
+ class RoomContext(BaseModel):
15
+ """Contextual information about a room for hook and channel processing."""
16
+
17
+ room: Room
18
+ bindings: list[ChannelBinding] = Field(default_factory=list)
19
+ participants: list[Participant] = Field(default_factory=list)
20
+ recent_events: list[RoomEvent] = Field(default_factory=list)
21
+
22
+ def other_channels(self, exclude_channel_id: str) -> list[ChannelBinding]:
23
+ """Get all bindings except the specified channel."""
24
+ return [b for b in self.bindings if b.channel_id != exclude_channel_id]
25
+
26
+ def channels_by_type(self, channel_type: ChannelType) -> list[ChannelBinding]:
27
+ """Get all bindings of a specific channel type."""
28
+ return [b for b in self.bindings if b.channel_type == channel_type]
29
+
30
+ def get_binding(self, channel_id: str) -> ChannelBinding | None:
31
+ """Get the binding for a specific channel."""
32
+ for b in self.bindings:
33
+ if b.channel_id == channel_id:
34
+ return b
35
+ return None
@@ -0,0 +1,76 @@
1
+ """Delivery and provider result models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+ from roomkit.models.event import EventContent, RoomEvent
10
+
11
+
12
+ class ProviderResult(BaseModel):
13
+ """Result from a provider delivery attempt."""
14
+
15
+ success: bool
16
+ provider_message_id: str | None = None
17
+ error: str | None = None
18
+ metadata: dict[str, Any] = Field(default_factory=dict)
19
+
20
+
21
+ class InboundMessage(BaseModel):
22
+ """A message received from an external provider."""
23
+
24
+ channel_id: str
25
+ sender_id: str
26
+ content: EventContent
27
+ external_id: str | None = None
28
+ thread_id: str | None = None
29
+ idempotency_key: str | None = None
30
+ metadata: dict[str, Any] = Field(default_factory=dict)
31
+
32
+
33
+ class InboundResult(BaseModel):
34
+ """Result of processing an inbound message."""
35
+
36
+ event: RoomEvent | None = None
37
+ blocked: bool = False
38
+ reason: str | None = None
39
+
40
+
41
+ class DeliveryResult(BaseModel):
42
+ """Result of delivering an event to a channel."""
43
+
44
+ channel_id: str
45
+ success: bool
46
+ provider_result: ProviderResult | None = None
47
+ error: str | None = None
48
+
49
+
50
+ class DeliveryStatus(BaseModel):
51
+ """Status update for an outbound message from a provider webhook.
52
+
53
+ Providers send status webhooks when messages are sent, delivered, failed, etc.
54
+ Use this with the ON_DELIVERY_STATUS hook to track outbound message delivery.
55
+
56
+ Attributes:
57
+ provider: Provider name (e.g., "telnyx", "twilio").
58
+ message_id: Provider's unique message identifier.
59
+ status: Status string (e.g., "sent", "delivered", "failed").
60
+ recipient: Phone number/address the message was sent to.
61
+ sender: Phone number/address the message was sent from.
62
+ error_code: Provider-specific error code (if failed).
63
+ error_message: Human-readable error message (if failed).
64
+ timestamp: When the status was reported.
65
+ raw: Original webhook payload for debugging.
66
+ """
67
+
68
+ provider: str
69
+ message_id: str
70
+ status: str
71
+ recipient: str = ""
72
+ sender: str = ""
73
+ error_code: str | None = None
74
+ error_message: str | None = None
75
+ timestamp: str | None = None
76
+ raw: dict[str, Any] = Field(default_factory=dict)
@@ -0,0 +1,170 @@
1
+ """All string enums for RoomKit."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import StrEnum, unique
6
+
7
+
8
+ @unique
9
+ class ChannelType(StrEnum):
10
+ SMS = "sms"
11
+ MMS = "mms"
12
+ RCS = "rcs"
13
+ EMAIL = "email"
14
+ WHATSAPP = "whatsapp"
15
+ WEBSOCKET = "websocket"
16
+ AI = "ai"
17
+ VOICE = "voice"
18
+ PUSH = "push"
19
+ MESSENGER = "messenger"
20
+ WEBHOOK = "webhook"
21
+ SYSTEM = "system"
22
+
23
+
24
+ @unique
25
+ class ChannelCategory(StrEnum):
26
+ TRANSPORT = "transport"
27
+ INTELLIGENCE = "intelligence"
28
+
29
+
30
+ @unique
31
+ class ChannelDirection(StrEnum):
32
+ INBOUND = "inbound"
33
+ OUTBOUND = "outbound"
34
+ BIDIRECTIONAL = "bidirectional"
35
+
36
+
37
+ @unique
38
+ class ChannelMediaType(StrEnum):
39
+ TEXT = "text"
40
+ RICH = "rich"
41
+ MEDIA = "media"
42
+ AUDIO = "audio"
43
+ VIDEO = "video"
44
+ LOCATION = "location"
45
+ TEMPLATE = "template"
46
+
47
+
48
+ @unique
49
+ class EventType(StrEnum):
50
+ MESSAGE = "message"
51
+ SYSTEM = "system"
52
+ TYPING = "typing"
53
+ READ_RECEIPT = "read_receipt"
54
+ DELIVERY_RECEIPT = "delivery_receipt"
55
+ PRESENCE = "presence"
56
+ REACTION = "reaction"
57
+ EDIT = "edit"
58
+ DELETE = "delete"
59
+ # Participant lifecycle (RFC §5.1)
60
+ PARTICIPANT_JOINED = "participant_joined"
61
+ PARTICIPANT_LEFT = "participant_left"
62
+ PARTICIPANT_IDENTIFIED = "participant_identified"
63
+ # Channel lifecycle (RFC §3.7)
64
+ CHANNEL_ATTACHED = "channel_attached"
65
+ CHANNEL_DETACHED = "channel_detached"
66
+ CHANNEL_MUTED = "channel_muted"
67
+ CHANNEL_UNMUTED = "channel_unmuted"
68
+ CHANNEL_UPDATED = "channel_updated"
69
+ # Side effects
70
+ TASK_CREATED = "task_created"
71
+ OBSERVATION = "observation"
72
+
73
+
74
+ @unique
75
+ class EventStatus(StrEnum):
76
+ PENDING = "pending"
77
+ DELIVERED = "delivered"
78
+ READ = "read"
79
+ FAILED = "failed"
80
+ BLOCKED = "blocked"
81
+
82
+
83
+ @unique
84
+ class Access(StrEnum):
85
+ READ_WRITE = "read_write"
86
+ READ_ONLY = "read_only"
87
+ WRITE_ONLY = "write_only"
88
+ NONE = "none"
89
+
90
+
91
+ @unique
92
+ class IdentificationStatus(StrEnum):
93
+ IDENTIFIED = "identified"
94
+ PENDING = "pending"
95
+ AMBIGUOUS = "ambiguous"
96
+ UNKNOWN = "unknown"
97
+ CHALLENGE_SENT = "challenge_sent"
98
+ REJECTED = "rejected"
99
+
100
+
101
+ @unique
102
+ class ParticipantRole(StrEnum):
103
+ OWNER = "owner"
104
+ AGENT = "agent"
105
+ MEMBER = "member"
106
+ OBSERVER = "observer"
107
+ BOT = "bot"
108
+
109
+
110
+ @unique
111
+ class ParticipantStatus(StrEnum):
112
+ ACTIVE = "active"
113
+ INACTIVE = "inactive"
114
+ LEFT = "left"
115
+ BANNED = "banned"
116
+
117
+
118
+ @unique
119
+ class TaskStatus(StrEnum):
120
+ PENDING = "pending"
121
+ IN_PROGRESS = "in_progress"
122
+ COMPLETED = "completed"
123
+ FAILED = "failed"
124
+ CANCELLED = "cancelled"
125
+
126
+
127
+ @unique
128
+ class RoomStatus(StrEnum):
129
+ ACTIVE = "active"
130
+ PAUSED = "paused"
131
+ CLOSED = "closed"
132
+ ARCHIVED = "archived"
133
+
134
+
135
+ @unique
136
+ class DeliveryMode(StrEnum):
137
+ BROADCAST = "broadcast"
138
+ DIRECT = "direct"
139
+ ROUND_ROBIN = "round_robin"
140
+
141
+
142
+ @unique
143
+ class HookTrigger(StrEnum):
144
+ # Event pipeline (RFC §4.1)
145
+ BEFORE_BROADCAST = "before_broadcast"
146
+ AFTER_BROADCAST = "after_broadcast"
147
+ # Channel lifecycle (RFC §4.1)
148
+ ON_CHANNEL_ATTACHED = "on_channel_attached"
149
+ ON_CHANNEL_DETACHED = "on_channel_detached"
150
+ ON_CHANNEL_MUTED = "on_channel_muted"
151
+ ON_CHANNEL_UNMUTED = "on_channel_unmuted"
152
+ # Room lifecycle (RFC §4.1)
153
+ ON_ROOM_CREATED = "on_room_created"
154
+ ON_ROOM_PAUSED = "on_room_paused"
155
+ ON_ROOM_CLOSED = "on_room_closed"
156
+ # Identity (RFC §7.3)
157
+ ON_IDENTITY_AMBIGUOUS = "on_identity_ambiguous"
158
+ ON_IDENTITY_UNKNOWN = "on_identity_unknown"
159
+ ON_PARTICIPANT_IDENTIFIED = "on_participant_identified"
160
+ # Side effects
161
+ ON_TASK_CREATED = "on_task_created"
162
+ ON_ERROR = "on_error"
163
+ # Delivery status (outbound message tracking)
164
+ ON_DELIVERY_STATUS = "on_delivery_status"
165
+
166
+
167
+ @unique
168
+ class HookExecution(StrEnum):
169
+ SYNC = "sync"
170
+ ASYNC = "async"