Technical docs

Omni

Overview

Support reference for the current `/omni` inbox implementation.

Routes and thread loading

  • Main routes:
  • `/omni`
  • `/omni/{conversation_id}`
  • Both routes render the same page component.
  • Queue loading uses:
  • `GET /api/organizations/{orgId}/conversations/`
  • Direct `/omni/{conversation_id}` navigation does extra fetches when that thread is not already in the loaded queue:
  • `GET /api/organizations/{orgId}/conversations/{conversation_id}/`
  • If that direct fetch succeeds, the frontend inserts the result as a detached thread and selects it.
  • This means a direct conversation URL can open a thread that is not present in the current queue result set.

Queue scope and filters

  • The backend Omni queue action currently includes:
  • `api`
  • `web_chat`
  • `telegram`
  • Queue pagination is backend-driven at `20` conversations per page.
  • Footer filter badges currently map to backend `filter` query params:
  • `Mine`
  • `Human`
  • `Waiting`
  • `Escalated`
  • `AI`
  • The queue header also exposes channel-category UI:
  • `All chats`
  • `External`
  • `Internal`
  • The frontend still sends `channel_category`, but the current backend conversations list action ignores it.
  • Result: the channel-category toggle is UX-only right now.

Queue groups shown in the sidebar

  • Client-side group labels are:
  • `Mine`
  • `Ally`
  • `Snoozed`
  • `Resolved`
  • `Spam`
  • Grouping is frontend-only:
  • AI-owned threads go to `Ally`
  • human-owned threads go to `Mine`
  • `resolved`, `snoozed`, and `spam` use local thread status
  • `Spam` exists in the thread model, but the current Omni queue API does not expose a spam filter/state transition.

Conversation customer/title mapping

  • Conversation payloads now include `participants[]` as the source of truth for membership.
  • The frontend currently derives the thread's primary customer from the first active `contact_channel` participant.
  • The transitional conversation-level `contact_channel` / `contact_channel_id` fields still exist for 1:1 compatibility, but group-capable conversation handling is moving toward `participants[]`.
  • Conversation payloads can include:
  • `title`
  • `temporary_title`
  • `title_source`
  • Queue rows now render three visible metadata lines:
  • active participant roster on the first line
  • `thread.title || thread.temporaryTitle || 'Untitled chat'` on the second line
  • normalized last-message preview or `No messages yet` on the third line
  • For Telegram chats, private conversations keep no auto title.
  • For Telegram group and supergroup conversations, the backend keeps the conversation title synced to the latest available inbound Telegram chat title.
  • When Telegram topic context is present in the inbound payload, the auto title can include both the chat title and topic name.

Customer panel identity details

  • The customer profile identity card now shows a copyable external source user ID when `customer.sourceUserId` is present.
  • This external ID appears below the customer name in both the wide identity panel and the compact popover.

Message and transcript behavior

  • Opening a thread loads:
  • `GET /api/organizations/{orgId}/conversations/{conversation_id}/messages/?page=1`
  • Older history loads by incrementing `page`.
  • Message history pagination is `30` per page.
  • Omni skips rendering backend messages when:
  • `status === 'in_progress'`
  • content is empty and there are no attachments
  • System messages stay in the transcript.
  • Store logic excludes system messages from last-message preview recalculation.
  • For Telegram conversations, backend history and frontend live insertion both deduplicate retried/redelivered inbound messages using `tg_message_hash`.
  • When duplicate Telegram hashes exist in stored history, the backend prefers the row whose `employee_id` matches the conversation's `ai_employee_id`.
  • The Omni message DTO now includes:
  • `contact_channel_id` for contact-role messages
  • `tg_message_hash` for Telegram-backed messages
  • Backend sender resolution for contact-role messages is message-specific, not only conversation-specific:
  • full contact name when available
  • otherwise `auto_name`
  • otherwise linked user Google name
  • otherwise contact email
  • fallback `Contact`
  • Outgoing message bubbles show read-only feedback state when reaction fields are present:
  • `Liked`
  • `Disliked`
  • `Comment added` for disliked messages with `feedbackComment`
  • Omni send is still text-only:
  • the footer passes `enableAttachments={false}`
  • attached files are not sent from this page
  • In the Omni composer, `Enter` sends the message.
  • `Shift+Enter` and `Alt+Enter` insert a newline without sending.

Takeover, handoff, and local status actions

  • Manual takeover uses:
  • `POST /api/organizations/{orgId}/conversations/{conversation_id}/assign/`
  • `Back to AI` uses:
  • `POST /api/organizations/{orgId}/conversations/{conversation_id}/unassign/`
  • The footer notice while AI owns the thread is:
  • `AI is handling this thread.` with action `Take over`
  • The header action for human-owned threads is:
  • `Back to AI`
  • Resolve and snooze are currently local store transitions in Omni.
  • Wake-from-snooze is also local store behavior unless a real backend conversation event replaces it.
  • The frontend does not call a resolve/snooze/spam backend conversation route from this page.
  • The backend still exposes automation control:
  • `PATCH /api/organizations/{orgId}/conversations/{conversation_id}/automation/`
  • The current Omni UI uses assign/unassign, not the automation patch route, for human/AI ownership switches.

WebSocket events Omni consumes

  • `conversation.message_sent`
  • `conversation.message_updated`
  • `conversation.message_deleted`
  • `conversation.updated`
  • `contact.updated`
  • Queue counts are read from `payload.meta.counts` when present.

Shortcut drift worth knowing

  • The help dialog currently lists:
  • `F1`
  • `Ctrl/Cmd + 1-9`
  • `Ctrl/Cmd + Up/Down`
  • `Ctrl/Cmd + T`
  • `Ctrl/Cmd + H`
  • `Ctrl/Cmd + Shift + R`
  • `Ctrl/Cmd + Shift + S`
  • `Esc`
  • `Ctrl/Cmd + Enter`
  • The dedicated Omni keyboard hook currently wires:
  • `F1`
  • `Ctrl/Cmd + 1-9`
  • `Ctrl/Cmd + Up/Down`
  • `Ctrl/Cmd + H`
  • `Ctrl/Cmd + Shift + R`
  • `Ctrl/Cmd + Shift + S`
  • `Esc`
  • `Ctrl/Cmd + T` is listed but not implemented in the Omni shortcut hook.

Start building your AI team