Inline Reply Suggestions
When you click an inbound message in the communication feed, an inline suggestions panel appears directly below it. The panel shows three AI-generated reply cards ranked by confidence, with controls to generate, regenerate, and use suggestions.
How It Works
Section titled “How It Works”Click inbound message bubble → Toggle InlineSuggestionsPanel below the bubble → GET /api/text-agents/suggestions/{message_id} → If suggestions exist → render 3 cards with confidence badges → If none exist → show "Generate Suggestions" button → Click generate → POST /api/text-agents/generate-suggestions → Agentic AI loop produces 3 ranked replies → Click "Use This Reply" → populate compose bar with suggestion textUI States
Section titled “UI States”The panel cycles through five states depending on data availability and user actions:
| State | Trigger | Display |
|---|---|---|
| Loading | Panel opens, fetching data | Three skeleton placeholder cards |
| Empty | No suggestions saved yet | Sparkles icon + “Generate Suggestions” button |
| Generating | Generate/regenerate clicked | Spinner + “Generating suggestions…” + skeletons |
| Loaded | Suggestions returned | Three cards in a responsive grid |
| Error | API call failed | Error message + “Try Again” button |
Suggestion Cards
Section titled “Suggestion Cards”Each card displays three elements:
pub struct TextAgentSuggestionItem { pub body: String, // The suggested reply text pub confidence: f64, // Score between 0.0 and 1.0}Confidence badges use color-coded thresholds:
- ≥ 80% — green badge (
emerald-500) - 50–79% — blue badge (
primary) - < 50% — gray badge (
muted)
The “Use This Reply” button on each card calls the on_use handler, which populates the compose bar with that suggestion’s body text.
Inbound Bubble Interactions
Section titled “Inbound Bubble Interactions”Inbound message bubbles gained interactive behaviors to support the suggestions panel:
- Hover — a subtle ring highlight (
hover:ring-1 ring-primary/30) and sparkles icon appear - Click — toggles the suggestions panel for that message
- Selected state — active ring (
ring-1 ring-primary/40) persists while the panel is open - Toggle — clicking the same bubble again closes the panel
- Switch — clicking a different inbound bubble closes the previous panel and opens a new one
Selection resets automatically when you navigate to a different contact.
Auto-Scroll
Section titled “Auto-Scroll”The communication feed now auto-scrolls to the most recent message when:
- The conversation first loads
- A new message arrives via WebSocket
- You switch to a different contact
The scroll uses a reactive use_effect hook tied to the message list signal, with a short timeout to ensure the DOM has rendered before scrolling.
Authorization
Section titled “Authorization”Both suggestion endpoints use contact-based access control instead of text agent management permissions. You need permission to view the contact — not permission to manage text agents.
The system calls check_contact_access with ContactInstanceAction::View, which checks:
- The contact exists in the caller’s organization
- The caller has either
ContactInstancePermission::View(org-wide) orContactInstancePermission::ViewAssigned(restricted to assigned contacts)
Super-admins and org owners bypass these checks automatically.
| Role | Can see suggestions? |
|---|---|
| Super admin / org owner | Always |
| Org admin with contact view permission | Yes, for all contacts |
| Org member assigned to the contact | Yes, via ViewAssigned |
| Org member not assigned to the contact | No (403 Forbidden) |
This means any team member who can view a contact’s conversation also sees AI suggestions for that contact’s messages — no separate text agent permission required.
API Endpoints
Section titled “API Endpoints”Get suggestions
Section titled “Get suggestions”GET /api/text-agents/suggestions/{message_id}Body/Query: { contact_id: string }Returns the most recent TextAgentSuggestion for the given message, or null if none exist. Requires ContactInstanceAction::View permission for the specified contact.
Status codes: 200 success, 400 invalid UUID, 403 no contact access, 500 server error.
Generate suggestions
Section titled “Generate suggestions”POST /api/text-agents/generate-suggestionsBody: { contact_id: string, message_id: string }Resolves the text agent assigned to the contact (via direct link or phone number fallback), runs the agentic suggestion loop, and persists the result to the text_agent_suggestion table. Requires ContactInstanceAction::View permission for the specified contact.
Status codes: 200 success, 400 invalid UUID, 403 no contact access, 404 message or contact not found, 500 server error.
Email Channel Formatting
Section titled “Email Channel Formatting”When generating suggestions for an Email message, the AI prompt includes an additional formatting hint:
Format as a proper email: open with a greeting, write 1–3 short paragraphs, and close with a sign-off.
This ensures email replies include a greeting, body paragraphs, and a sign-off — instead of the short, SMS-style responses used for other channels. The hint is injected automatically based on the message’s channel — no configuration needed.
Example email suggestion:
Hi John,
Thank you for reaching out about your account. I've reviewedthe details and everything looks good on our end.
Please let me know if you have any other questions.
Best regards,Support TeamSMS and WhatsApp suggestions remain short and conversational — the formatting hint only applies to MessageChannel::Email.
Key Components
Section titled “Key Components”| Component | File | Role |
|---|---|---|
InlineSuggestionsPanel | text_agent/components/text_agent_suggestions_panel_component.rs | Panel with fetch, generate, and card rendering |
SuggestionCard | Same file (private) | Single card with confidence badge and use button |
SkeletonCards | Same file (private) | Three animated placeholder cards |
MessageEntry | messaging/components/message_entry_component.rs | Bubble with click, hover, and selection states |
CommunicationFeed | messaging/components/communication_feed_component.rs | Feed container managing selection state and auto-scroll |
Database
Section titled “Database”Suggestions are persisted in the text_agent_suggestion table:
text_agent_suggestion ( id UUID PRIMARY KEY, organization_id UUID NOT NULL, contact_id UUID NOT NULL, text_agent_id UUID NOT NULL, message_id UUID NOT NULL, suggestions JSONB NOT NULL, -- Vec<TextAgentSuggestionItem> auto_sent_body TEXT, -- Set if auto-reply was triggered created_at TIMESTAMP NOT NULL)Each generation creates a new row. The GET endpoint returns the most recent row for a given message_id, ordered by created_at DESC.