Configuration
Text agents are created and managed from the Text Agents section of the dashboard. Each agent belongs to the organization and is shared across all org members.
Creating an Agent
Section titled “Creating an Agent”- Go to Text Agents in the sidebar
- Click New Agent
- Fill in the fields (see below)
- Click Create
POST /api/text-agentspub struct TextAgentData { pub name: String, pub purpose: String, pub tier: TextAgentTier, pub model: TextAgentModel, pub knowledge_base_ids: Vec<Uuid>, pub confidence_threshold: f64, pub custom_instructions: Option<String>, pub escalation_instructions: Option<String>, pub restricted_topics: Option<String>, pub temperature: Option<i32>, // 0–100 integer scale → divided by 100 for LLM}Agent Fields
Section titled “Agent Fields”A human-readable label. Shown in the agent list, contact sidebar dropdowns, and channel default badges.
Purpose
Section titled “Purpose”The core system prompt. Defines who the agent is, how it behaves, and what it’s for. This is the most important field.
Example:
You are an assistant for Acme Dental. Respond warmly and professionally.Help patients reschedule appointments, answer questions about services,and direct urgent issues to call the front desk at (555) 100-2000.Keep replies under 160 characters when possible.The purpose is injected at the top of the system prompt under # Role, followed by behavioral rules, org context, contact info, and output instructions.
Custom Instructions
Section titled “Custom Instructions”Free-form instructions appended to the agent’s system prompt under ## Custom Instructions. Use this to override tone, enforce formatting rules, or add context that applies to all conversations.
Example:
- Always sign off with "— Acme Support"- Never promise specific refund timelines- If the contact mentions a competitor, redirect to our value propositionEmpty values are omitted from the prompt entirely.
Escalation Instructions
Section titled “Escalation Instructions”Instructions for what the agent should do when it cannot answer confidently. Injected under ## Escalation in the system prompt.
Example:
If you are unsure, ask the contact to call us directly at (555) 100-2000or say "Let me connect you with our team for more details."Restricted Topics
Section titled “Restricted Topics”Topics the agent must refuse to discuss. Injected under ## Restricted Topics. The agent is instructed to politely decline and redirect the conversation.
Example:
- Competitor pricing- Internal company financials- Legal advice or medical diagnosespub enum TextAgentTier { GlobalDefault, Premium, Mid,}Tiers group models by quality and cost rather than provider. Changing the tier resets the model selection to that tier’s default.
| Tier | Behavior |
|---|---|
| Global Default | Uses the model configured by an admin in Admin → AI Models → Text Agent Suggestions |
| Premium | High-quality, higher-cost models |
| Mid | Balanced quality and cost |
When you select Global Default, the model selector disappears — the admin-configured model applies automatically.
Models are filtered by the selected tier. The model selector only appears when the tier is Premium or Mid.
Premium models:
| Display Name | OpenRouter ID | Default |
|---|---|---|
| GPT-5.4 | openai/gpt-5.4 | ✓ |
| Claude Opus 4.6 | anthropic/claude-opus-4.6 | |
| Gemini 3.1 Pro | google/gemini-3.1-pro-preview |
Mid models:
| Display Name | OpenRouter ID | Default |
|---|---|---|
| GPT-5.4 Mini | openai/gpt-5.4-mini | ✓ |
| Claude Haiku 4.5 | anthropic/claude-haiku-4.5 | |
| GPT-5.4 Nano | openai/gpt-5.4-nano | |
| Gemini 3.1 Flash Lite | google/gemini-3.1-flash-lite-preview | |
| DeepSeek V3.2 | deepseek/deepseek-v3.2 |
All models are routed through OpenRouter using a single openrouter_api_key from core_conf.
Model Resolution
Section titled “Model Resolution”At runtime, the system resolves which model to use in this order:
- Per-agent model — if the agent has a specific model set (Premium or Mid tier), use it directly
- Admin global default — if the agent uses
GlobalDefault, query theai_model_configtable for thetext_agent_suggestionsarea - Hardcoded fallback — if no admin config exists, fall back to
google/gemini-3.1-pro-preview
let model_id = match agent_model.openrouter_id() { Some(id) => id.to_string(), None => resolve_model(AiArea::TextAgentSuggestions).await?,};Admin Global Default
Section titled “Admin Global Default”Admins configure the global default model from Admin → AI Models. The Text Agent Suggestions row appears under the “Text Agent” tier group. This setting applies to all text agents using the GlobalDefault tier.
The admin can select any available model from the OpenRouter catalog. The selection is stored in the ai_model_config table:
-- area = "text_agent_suggestions", model_id = "openai/gpt-5.4"SELECT model_id FROM ai_model_config WHERE area = 'text_agent_suggestions';Confidence Threshold
Section titled “Confidence Threshold”A float between 0.0 and 1.0 (default: 0.7).
Used only when auto-reply is enabled on a contact assignment. The agent compares the highest-confidence suggestion against this threshold:
| Condition | Behavior |
|---|---|
confidence ≥ threshold | Auto-reply sent cleanly |
confidence < threshold | Reply still sent, but a warning alert note is added to the contact |
Temperature
Section titled “Temperature”Controls LLM output randomness. Stored as an integer from 0 to 100 and divided by 100 before sending to the provider (50 → 0.50).
- Lower values (0–30) — more focused, deterministic replies
- Higher values (70–100) — more varied, creative replies
- Leave unset — uses the provider’s default temperature
Temperature is in the Advanced section of the form, collapsed by default. A “Reset to default” button clears the value back to unset.
pub const DEFAULT_TEMPERATURE_DISPLAY: i32 = 50; // shown when slider is first openedKnowledge Bases
Section titled “Knowledge Bases”A list of knowledge base IDs the agent can query during the agentic loop. The agent uses a query_knowledge tool call (backed by handle_query_knowledge_tool_call) to look up factual information before composing replies.
The tool accepts Vec<Uuid> and searches all linked knowledge bases simultaneously. Documents are fetched, formatted, and sent to GPT-4.1 Mini as a focused retrieval step — keeping the primary model’s context window clean.
Multiple knowledge bases can be linked to one agent. They’re stored as a JSON array in the knowledge_base_ids column.
System Prompt Layout
Section titled “System Prompt Layout”The full system prompt assembled at runtime follows this structure:
# RoleYou are {name}.Purpose: {purpose}Channel: SMS
## Custom Instructions{custom_instructions}
## EscalationWhen you cannot confidently answer…{escalation_instructions}
## Restricted TopicsYou must refuse to discuss…{restricted_topics}
## Organization{org_context}
## Contact- Name: …- Phone: …- Tags: …
## Contact Notes{notes}
## TaskGenerate exactly 3 distinct reply suggestions…Sections with no content are omitted entirely.
Editing an Agent
Section titled “Editing an Agent”Navigate to any agent → its detail view. All fields are editable. Changes save via:
PUT /api/text-agents/{id}The detail view also includes:
- Channel Defaults — set this agent as the org-wide default for SMS and/or WhatsApp
- Delete — removes the agent and cascades to all contact assignments and saved suggestions
Agent List View
Section titled “Agent List View”The list shows all agents as cards with name, purpose excerpt, and tier/model badge (e.g., “Premium / GPT-5.4” or “Global Default / Global Default”).
Data Model
Section titled “Data Model”CREATE TABLE text_agent ( id UUID PRIMARY KEY, organization_id UUID NOT NULL REFERENCES organization(id) ON DELETE CASCADE, name TEXT NOT NULL, purpose TEXT NOT NULL, provider TEXT NOT NULL, model TEXT NOT NULL, knowledge_base_ids JSONB NOT NULL DEFAULT '[]', confidence_threshold FLOAT NOT NULL DEFAULT 0.7, custom_instructions TEXT, escalation_instructions TEXT, restricted_topics TEXT, temperature INTEGER, -- 0–100; NULL = provider default created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL);Permissions
Section titled “Permissions”| Action | Permission Required |
|---|---|
| Create agent | TextAgent:Collection:Create |
| View agent | TextAgent:Instance:View |
| Update agent | TextAgent:Instance:Update |
| Delete agent | TextAgent:Instance:Delete |
Org owners bypass all permission checks.
Module Structure
Section titled “Module Structure”src/mods/text_agent/├── types/│ ├── text_agent_type.rs # TextAgent domain struct│ ├── text_agent_data_type.rs # TextAgentData (create/update input)│ ├── text_agent_tier_type.rs # TextAgentTier enum (Global Default, Premium, Mid)│ └── text_agent_model_type.rs # TextAgentModel enum + tier grouping + backward compat├── api/│ ├── create_text_agent_api.rs # POST /api/text-agents│ ├── get_text_agents_api.rs # GET /api/text-agents│ ├── get_text_agent_api.rs # GET /api/text-agents/{id}│ ├── update_text_agent_api.rs # PUT /api/text-agents/{id}│ └── delete_text_agent_api.rs # DELETE /api/text-agents/{id}├── components/│ └── text_agent_form_component.rs # Shared create/edit form└── services/ ├── build_text_agent_context_service.rs # Assembles the system prompt └── generate_text_agent_suggestions_service.rs # Agentic loop + KB tool