Agent Builder — Developer Guide
The Agent Builder replaces the old BotConfigPage with an 8-tab configuration experience. It extends the BotConfiguration Prisma model with ~35 new fields and enhances the 3-step conversation brain pipeline to use all configured values.
Architecture
┌─────────────────────────────────────────────┐
│ AgentBuilderPage.tsx (tab container) │
│ ┌──────┬──────┬──────┬──────┬──────┬────┐ │
│ │Ident │Know │Sales │Supp │Media │... │ │
│ └──┬───┴──┬───┴──┬───┴──┬───┴──┬───┴────┘ │
│ └──────┴──────┴──────┴──────┘ │
│ ▼ single state object │
│ BotConfiguration │
│ ▼ PUT /ice/bot-config │
└─────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ conversation-brain.service.ts │
│ buildAgentContextSections(botConfig) │
│ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │decideAct │→│generateRe│→│compliance │ │
│ │ion │ │ply │ │Filter │ │
│ └──────────┘ └──────────┘ └────────────┘ │
└─────────────────────────────────────────────┘
Key design decisions:
- Single state object: All 8 tabs modify one
BotConfiguration. No intermediate saves. - No new API endpoints: The existing
GET/PUT /ice/bot-confighandles everything via generic upsert (Record<string, unknown>+as anycast). - Brain integration via
buildAgentContextSections(): A typed helper extracts all config into prompt sections, keeping the pipeline functions clean.
Schema (Prisma)
New fields added to the BotConfiguration model, organized by section:
Identity & Personality
| Field | Type | Description |
|---|---|---|
agentName | String? | Display name for the AI agent |
agentAvatar | String? | Avatar URL |
systemPrompt | String? | Master instruction prompt (up to 5000 chars) |
personality | Json? | AgentPersonality — humor, formality, emojiUsage, verbosity (0-100 each) |
supportedLanguages | String[] | ISO language codes the agent supports |
autoDetectLanguage | Boolean | Auto-detect customer language (default: true) |
Business Knowledge
| Field | Type | Description |
|---|---|---|
companyDescription | String? | Company story for context |
businessPolicies | Json? | AgentPolicies — return, refund, shipping, warranty |
storeLocations | Json? | StoreLocation[] — id, name, address, phone, hours, lat/lng |
customInstructions | String? | Additional directives |
documentUrls | String[] | URLs to external knowledge documents |
pricingRules | Json? | AgentPricingRules — canQuotePrices, currency, showTax |
Sales & Commerce
| Field | Type | Description |
|---|---|---|
salesEnabled | Boolean | Master sales toggle |
connectedStoreIds | String[] | Linked e-commerce store IDs |
maxDiscountPercent | Float? | Max autonomous discount |
allowedPromoCodes | String[] | Whitelisted promo codes |
upsellRules | Json? | UpsellRule[] — trigger + message |
bundleOffers | Json? | BundleOffer[] — name, discount, description |
discountAuthority | Json? | DiscountAuthority — enabled, max %, max fixed, currency |
crossSellEnabled | Boolean | Enable cross-sell suggestions |
cartBuildingEnabled | Boolean | Enable in-chat cart building |
cartAbandonmentEnabled | Boolean | Enable cart abandonment follow-ups |
commentToPurchaseFlow | Boolean | Enable comment-to-purchase |
leadQualification | Json? | LeadQualification — enabled, scoringThreshold |
closingTechniques | Json? | ClosingTechniques — urgency, socialProof, scarcity |
objectionHandling | Json? | ObjectionHandler[] — objection, response, category |
Support & Problem Solving
| Field | Type | Description |
|---|---|---|
complaintFlows | Json? | ComplaintFlow[] — trigger + step toggles |
refundAuthority | Json? | RefundAuthority — enabled, maxAmount, approvalAbove, currency |
shippingIssueHandling | Json? | ShippingIssueHandling — autoLookup, offerCompensation, maxCompensation |
approvalWorkflowId | String? | Linked approval workflow |
handoffProtocol | Json? | HandoffProtocol — message, assignToRole, preserveTranscript |
followUpScheduling | Json? | FollowUpScheduling — enabled, delayHours, maxFollowUps |
conversationGoals | String[] | Goal tags (convert_to_sale, resolve_complaint, etc.) |
Media & Rich Content
| Field | Type | Description |
|---|---|---|
voiceEnabled | Boolean | Process voice messages |
voiceLanguages | String[] | Transcription language codes |
voiceReplyFormat | String | text, voice, or both (default: text) |
imageEnabled | Boolean | Process images |
imageUseCases | String[] | product_lookup, damage_detection, receipt_parse, visual_search |
videoEnabled | Boolean | Process video |
videoMaxDuration | Int? | Max video length in seconds |
locationEnabled | Boolean | Process location pins |
documentEnabled | Boolean | Process document attachments |
documentTypes | String[] | receipt, invoice, warranty_card, id |
unsupportedMediaMessage | String? | Fallback for unsupported media |
Platform-Specific Behavior
| Field | Type | Description |
|---|---|---|
platformBehaviors | Json? | Record<string, PlatformBehavior> — per-platform config |
Each PlatformBehavior contains: enabled, toneOverride, maxReplyLength, features (object of boolean toggles).
Safety (Extended)
| Field | Type | Description |
|---|---|---|
neverSayPhrases | String[] | Forbidden words/phrases |
actionsRequiringApproval | Json? | ApprovalAction[] — action, threshold, approverRole |
dataPrivacyRules | Json? | DataPrivacyRules — canReference flags, gdprMode, dataRetentionDays |
industryCompliance | Json? | IndustryCompliance — type, restrictions, disclaimers |
auditTrailEnabled | Boolean | Enable audit logging (default: true) |
Shared Types
All types are in packages/shared/src/types/ice.types.ts and exported from packages/shared/src/index.ts.
Key interfaces: AgentPersonality, AgentPolicies, StoreLocation, AgentPricingRules, UpsellRule, BundleOffer, DiscountAuthority, LeadQualification, ClosingTechniques, ObjectionHandler, ComplaintFlow, RefundAuthority, ShippingIssueHandling, HandoffProtocol, FollowUpScheduling, PlatformBehavior, ApprovalAction, DataPrivacyRules, IndustryCompliance.
Type aliases: VoiceReplyFormat, ImageUseCase, DocumentParseType.
Zod Validators
Extended validators in packages/shared/src/validators/ice.schema.ts:
// Example: personality validator
personality: z.object({
humor: z.number().min(0).max(100),
formality: z.number().min(0).max(100),
emojiUsage: z.number().min(0).max(100),
verbosity: z.number().min(0).max(100),
}).optional(),
// Example: store location validator
storeLocations: z.array(z.object({
id: z.string(),
name: z.string(),
address: z.string(),
phone: z.string().optional(),
hours: z.string().optional(),
lat: z.number().optional(),
lng: z.number().optional(),
})).optional(),
All new fields are .optional() or .nullable() to maintain backward compatibility.
Brain Pipeline Integration
The conversation-brain.service.ts uses a buildAgentContextSections() helper to extract all Agent Builder config into typed prompt sections:
function buildAgentContextSections(bc: Record<string, unknown>) {
const str = (key: string) => (typeof bc[key] === 'string' ? bc[key] as string : '');
const json = (key: string) => {
const v = bc[key];
return v && typeof v === 'object' ? JSON.stringify(v) : '';
};
// ... returns sections object
}
decideAction — Injected Sections
- System prompt and company description
- Custom instructions
- Business policies (JSON)
- Upsell rules and discount authority
- Objection handling playbook
- Complaint flows and refund authority
- Conversation goals
- Media capabilities (voice, images, video)
- Closing techniques
generateReply — Injected Sections
- Personality sliders (
Humor=80/100, Formality=20/100, etc.) - Supported languages with auto-detect flag
- Platform-specific tone override and max reply length
- Handoff protocol
- Closing techniques
complianceFilter — Injected Rules
- Never-say phrases with
NEVER use these wordsdirective - Data privacy rules (what data can/cannot be referenced)
- Industry compliance restrictions and disclaimers
- Three additional filter rules (Rules 7, 8, 9)
Frontend Architecture
Tab Container — AgentBuilderPage.tsx
apps/web/src/pages/conversation-engine/
├── AgentBuilderPage.tsx # Main container with 8 tabs
├── agent-builder/
│ ├── IdentityTab.tsx # Persona, personality, languages, settings
│ ├── KnowledgeTab.tsx # Company story, policies, FAQ, locations
│ ├── SalesTab.tsx # Commerce, discounts, upsell, bundles
│ ├── SupportTab.tsx # Objections, complaints, refunds, handoff
│ ├── MediaTab.tsx # Voice, images, video, documents
│ ├── PlatformsTab.tsx # Per-platform behavior cards
│ ├── PerformanceTab.tsx # Stats dashboard
│ └── SafetyTab.tsx # Blocked topics, privacy, compliance
└── __tests__/
└── AgentBuilderPage.test.tsx # 6 tests
State pattern: AgentBuilderPage loads the config once via iceApi.getBotConfig(), holds it in useState, and passes config + onChange to each tab. Tabs call onChange(partialUpdates) which merges into the parent state. A single Save button calls iceApi.updateBotConfig(config).
Dirty tracking: The page tracks whether any changes have been made since load, showing an unsaved indicator dot and disabling/enabling the save button accordingly.
Route Registration
In apps/web/src/routes/index.tsx, the old BotConfigPage import was replaced:
import { AgentBuilderPage } from '@/pages/conversation-engine/AgentBuilderPage';
// Route element: <AgentBuilderPage />
API
No new endpoints. The existing endpoints handle all Agent Builder data:
| Method | Endpoint | Description |
|---|---|---|
GET | /ice/bot-config | Fetch full BotConfiguration |
PUT | /ice/bot-config | Upsert with partial updates |
The updateBotConfig service uses Record<string, unknown> + as any for the Prisma upsert, so all new fields pass through automatically without backend changes.
i18n
All strings use the ice namespace:
pages.ice.agentBuilder.tabs.*— Tab labelspages.ice.agentBuilder.identity.*— Identity tabpages.ice.agentBuilder.knowledge.*— Knowledge tabpages.ice.agentBuilder.sales.*— Sales tabpages.ice.agentBuilder.support.*— Support tabpages.ice.agentBuilder.media.*— Media tabpages.ice.agentBuilder.platforms.*— Platforms tabpages.ice.agentBuilder.performance.*— Performance tabpages.ice.agentBuilder.safety.*— Safety tab
Both en/ice.json and ar/ice.json are fully translated (~200 new keys each).
Tests
Backend — conversation-brain.service.test.ts (9 tests)
- Successful 3-step pipeline returns reply text
- Heuristic fallback when LLM call fails
- System prompt injection into decision prompt
- Company description injection
- Never-say phrases in compliance filter
- Objection handling in decision prompt
- Media capabilities in decision prompt
- Heuristic fallback for unparseable LLM response
- Personality sliders in generation prompt
Frontend — AgentBuilderPage.test.tsx (6 tests)
- Renders agent builder with tabs
- All 8 tab buttons displayed
- Identity tab shown by default
- Master enable toggle present
- Save button present
- Back link present
Migration
After deploying, run the Prisma migration to add all new fields:
cd apps/api
npx prisma migrate dev --name agent_builder_fields
All new fields are optional with sensible defaults, so existing BotConfiguration rows remain valid.