Developer Guide
This guide covers the technical implementation of Assistant Routing, including data models, the webhook API, and the routing service architecture.
Architecture Overview
Assistant Routing connects incoming webhook messages to CX Assistants through a multi-step process:
Data Model
AssistantRoute
The AssistantRoute model maps message metadata to Assistants using JsonLogic expressions.
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Auto | Primary key |
assistant | ForeignKey | Yes | Reference to the Assistant that handles matching messages |
tags | JSON | Yes | JsonLogic expression for matching message tags |
created_at | datetime | Auto | Timestamp when the route was created |
updated_at | datetime | Auto | Timestamp when the route was last updated |
Django Model Definition:
class AssistantRoute(TimestampedModel):
assistant = models.ForeignKey(Assistant, on_delete=models.CASCADE)
tags = models.JSONField(default=dict, blank=True)
def __str__(self) -> str:
return f"{self.assistant} - {self.tags}"
ConversationAssistantThread
Tracks which Assistant is active for a given conversation.
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Auto | Primary key |
assistant_thread | ForeignKey | Yes | Reference to the AssistantThread |
conversation | ForeignKey | Yes | Reference to the Conversation |
deactivated_at | datetime | No | When the assistant was deactivated for this conversation |
created_at | datetime | Auto | Timestamp when the association was created |
updated_at | datetime | Auto | Timestamp when the association was last updated |
Message
The internal representation of an incoming message used by the routing service.
| Field | Type | Description |
|---|---|---|
external_conversation_id | string | The CX platform's conversation identifier |
message_id | string | Unique message identifier |
time | datetime | Message timestamp |
author_id | string | Identifier of the message author |
source | MessageSource | Either visitor or agent |
text | string | Message content |
tags | dict | Metadata key-value pairs used for routing |
API Reference
Webhook Endpoint
Receives messages from the CX platform and triggers routing.
POST /api/v2/assistants/webhook
GET /api/v2/assistants/webhook
This endpoint accepts both GET and POST methods to accommodate different CX platform webhook implementations.
Request Flow
- Admin Service receives the webhook from the CX platform in the platform's native format
- Admin converts the message to the generic format
- Admin forwards the message to Backend via this endpoint
- Backend processes the message asynchronously
Response
The endpoint returns immediately with HTTP 200 OK. Processing happens asynchronously in the background.
HTTP/1.1 200 OK
The webhook endpoint returns immediately to prevent timeout issues with CX platforms. Message processing and Assistant evaluation happen asynchronously.
Routing Service
The AssistantRoutingService is responsible for:
- Finding the active Assistant for a conversation
- Matching message tags against configured routes
- Activating/deactivating Assistants for conversations
- Triggering Assistant evaluation for visitor messages
- Sending responses back to the CX platform
Key Methods
handle_message
async def handle_message(
self,
message: Message,
platform_adapter: CxPlatformAdapter
) -> None
Main entry point for processing incoming messages. Only processes messages from visitors (not agents).
_find_active_assistant
async def _find_active_assistant(
self,
conversation_id: str,
tags: dict
) -> Assistant | None
Determines which Assistant should handle the conversation:
- Checks for an existing active Assistant
- Finds a route matching the message tags
- Handles activation/deactivation logic based on route changes
Route Matching Logic
Routes are matched using JsonLogic expressions evaluated against message tags:
async def find_assistant_for_route(
self,
tags: dict,
include_details: bool = True
) -> Assistant | None:
orm_assistant_routes = orm.AssistantRoute.objects.filter().all()
async for orm_assistant_route in orm_assistant_routes:
if jsonLogic(orm_assistant_route.tags, tags):
return await _assistant_from_orm(orm_assistant_route.assistant)
return None
The first route that matches (in database order) is used.
Platform Adapters
Platform adapters implement the CxPlatformAdapter interface to send responses back to the CX platform:
class CxPlatformAdapter(ABC):
@abstractmethod
async def send_message(
self,
text: str,
reply_to_message: Message,
agent_id: str | None = None
) -> None:
pass
@abstractmethod
async def transfer_to_human(
self,
external_conversation_id: str
) -> None:
pass
Each supported CX platform has its own adapter implementation that handles:
- Authentication with the platform API
- Message formatting specific to the platform
- Error handling and retries
Implementation Details
Activation and Deactivation
When a route matches for the first time:
- An
AssistantThreadis created or retrieved for the conversation - A
ConversationAssistantThreadrecord links the thread to the conversation - The Assistant is now "active" for this conversation
When the route no longer matches (tags changed):
- The
ConversationAssistantThread.deactivated_atfield is set - The Assistant stops processing messages for this conversation
- If a different route matches, the new Assistant is activated
Message Processing
Only visitor messages trigger Assistant evaluation. Agent messages are ignored by the routing service but are still ingested and stored for conversation context.
Impersonation
Assistants can be configured with an impersonation_agent_id to send messages as a specific agent in the CX platform. This is useful for:
- Making bot messages appear to come from a specific team member
- Maintaining consistent identity across automated responses
Source Code References
| Component | Location |
|---|---|
| AssistantRoute model | assistants/models.py:369-374 |
| AssistantRoutingService | backend/domains/assistants/services/routing.py |
| AssistantRepository | backend/domains/assistants/repositories/assistant.py |
| WebhookService | backend/domains/assistants/services/webhook.py |
| Webhook endpoint | backend/domains/assistants/routes.py:172-185 |
| Platform adapters | backend/domains/assistants/services/platforms/ |
Related Documentation
- Overview: Conceptual overview
- User Guide: Configuration instructions
- JsonLogic: Tag matching expression syntax
- Data Ingestion: How messages are received from CX platforms
- Assistants Developer Guide: Assistant configuration and evaluation