Skip to main content
Integrate AI agents into your iOS app to provide intelligent conversational experiences with chat history, contextual responses, and seamless handoffs.

Prerequisites

Before implementing AI agents, ensure you have:

Overview

The AI Agent integration provides:
  • Intelligent Responses - Context-aware AI conversations
  • Chat History - Browse and resume previous AI sessions
  • Streaming Responses - Real-time message streaming
  • Custom Styling - Match your app’s design
  • Suggested Messages - Quick-start prompts for users

Basic Implementation

Create a simple AI chat screen:
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class AIAgentChatViewController: UIViewController {
    
    private var user: User?
    private var messageHeader: CometChatMessageHeader!
    private var messageList: CometChatMessageList!
    private var messageComposer: CometChatMessageComposer!
    
    convenience init(user: User) {
        self.init()
        self.user = user
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        setupUI()
    }
    
    private func setupUI() {
        guard let user = user else { return }
        
        // Message Header
        messageHeader = CometChatMessageHeader()
        messageHeader.set(user: user)
        messageHeader.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(messageHeader)
        
        // Message List
        messageList = CometChatMessageList()
        messageList.set(user: user)
        messageList.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(messageList)
        
        // Message Composer
        messageComposer = CometChatMessageComposer()
        messageComposer.set(user: user)
        messageComposer.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(messageComposer)
        
        setupConstraints()
    }
    
    private func setupConstraints() {
        NSLayoutConstraint.activate([
            messageHeader.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            messageHeader.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            messageHeader.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            messageHeader.heightAnchor.constraint(equalToConstant: 60),
            
            messageList.topAnchor.constraint(equalTo: messageHeader.bottomAnchor),
            messageList.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            messageList.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            messageList.bottomAnchor.constraint(equalTo: messageComposer.topAnchor),
            
            messageComposer.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            messageComposer.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            messageComposer.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
    }
}

Production Implementation

Complete AI agent chat with history, navigation, and error handling:
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class ProductionAIAgentViewController: UIViewController {
    
    // MARK: - Properties
    private var user: User?
    private var group: Group?
    private var parentMessage: BaseMessage?
    private var isHistoryMode: Bool = false
    
    private var messageHeader: CometChatMessageHeader!
    private var messageList: CometChatMessageList!
    private var messageComposer: CometChatMessageComposer!
    
    // MARK: - Initialization
    convenience init(user: User, parentMessage: BaseMessage? = nil, isHistory: Bool = false) {
        self.init()
        self.user = user
        self.parentMessage = parentMessage
        self.isHistoryMode = isHistory
    }
    
    convenience init(group: Group, parentMessage: BaseMessage? = nil, isHistory: Bool = false) {
        self.init()
        self.group = group
        self.parentMessage = parentMessage
        self.isHistoryMode = isHistory
    }
    
    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        setupMessageHeader()
        setupMessageList()
        setupMessageComposer()
        setupConstraints()
    }
    
    // MARK: - Setup
    private func setupMessageHeader() {
        messageHeader = CometChatMessageHeader()
        messageHeader.translatesAutoresizingMaskIntoConstraints = false
        
        if let user = user {
            messageHeader.set(user: user)
        } else if let group = group {
            messageHeader.set(group: group)
        }
        
        // Back button handler
        messageHeader.set(onBack: { [weak self] in
            self?.navigationController?.popViewController(animated: true)
        })
        
        // Chat history button handler
        messageHeader.set(chatHistoryButtonClick: { [weak self] in
            self?.openChatHistory()
        })
        
        view.addSubview(messageHeader)
    }
    
    private func setupMessageList() {
        messageList = CometChatMessageList()
        messageList.translatesAutoresizingMaskIntoConstraints = false
        messageList.hideThreadView = true
        
        if let user = user {
            messageList.set(user: user)
        } else if let group = group {
            messageList.set(group: group)
        }
        
        // If resuming from history, set parent message
        if let parentMessage = parentMessage {
            messageList.set(parentMessage: parentMessage)
        }
        
        view.addSubview(messageList)
    }
    
    private func setupMessageComposer() {
        messageComposer = CometChatMessageComposer()
        messageComposer.translatesAutoresizingMaskIntoConstraints = false
        
        if let user = user {
            messageComposer.set(user: user)
        } else if let group = group {
            messageComposer.set(group: group)
        }
        
        // If resuming from history, set parent message
        if let parentMessage = parentMessage {
            messageComposer.set(parentMessage: parentMessage)
        }
        
        view.addSubview(messageComposer)
    }
    
    private func setupConstraints() {
        NSLayoutConstraint.activate([
            messageHeader.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            messageHeader.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            messageHeader.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            messageHeader.heightAnchor.constraint(equalToConstant: 60),
            
            messageList.topAnchor.constraint(equalTo: messageHeader.bottomAnchor),
            messageList.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            messageList.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            messageList.bottomAnchor.constraint(equalTo: messageComposer.topAnchor),
            
            messageComposer.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            messageComposer.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            messageComposer.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
    }
    
    // MARK: - Chat History
    private func openChatHistory() {
        let chatHistoryVC = CometChatAIAssistantChatHistory()
        
        if let user = user {
            chatHistoryVC.set(user: user)
        } else if let group = group {
            chatHistoryVC.set(group: group)
        }
        
        // Handle new chat button
        chatHistoryVC.set(onNewChatButtonClicked: { [weak self] in
            self?.startNewChat()
        })
        
        // Handle message selection to resume conversation
        chatHistoryVC.set(onMessageClicked: { [weak self] message in
            self?.resumeConversation(from: message)
        })
        
        // Handle close
        chatHistoryVC.set(onClose: { [weak self] in
            self?.navigationController?.popViewController(animated: true)
        })
        
        navigationController?.pushViewController(chatHistoryVC, animated: true)
    }
    
    private func startNewChat() {
        let newChatVC: ProductionAIAgentViewController
        
        if let user = user {
            newChatVC = ProductionAIAgentViewController(user: user)
        } else if let group = group {
            newChatVC = ProductionAIAgentViewController(group: group)
        } else {
            return
        }
        
        navigationController?.pushViewController(newChatVC, animated: true)
    }
    
    private func resumeConversation(from message: BaseMessage) {
        let resumeVC: ProductionAIAgentViewController
        
        if let user = user {
            resumeVC = ProductionAIAgentViewController(user: user, parentMessage: message, isHistory: true)
        } else if let group = group {
            resumeVC = ProductionAIAgentViewController(group: group, parentMessage: message, isHistory: true)
        } else {
            return
        }
        
        navigationController?.pushViewController(resumeVC, animated: true)
    }
}

Launching AI Agent Chat

Start an AI agent conversation from your app:
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class ChatListViewController: UIViewController {
    
    func openAIAgentChat(agentUID: String) {
        // Fetch the AI agent user
        CometChat.getUser(UID: agentUID) { [weak self] user in
            DispatchQueue.main.async {
                // Check if user is an AI agent (role contains "agentic")
                if user.role?.lowercased().contains("agentic") == true {
                    let aiChatVC = ProductionAIAgentViewController(user: user)
                    self?.navigationController?.pushViewController(aiChatVC, animated: true)
                } else {
                    // Regular user chat
                    let messages = CometChatMessages()
                    messages.set(user: user)
                    self?.navigationController?.pushViewController(messages, animated: true)
                }
            }
        } onError: { error in
            print("Error fetching user: \(error?.errorDescription ?? "")")
        }
    }
    
    func detectAndOpenChat(for user: User) {
        // Detect if user is an AI agent
        let isAIAgent = user.role?.lowercased().contains("agentic") == true
        
        if isAIAgent {
            let aiChatVC = ProductionAIAgentViewController(user: user)
            navigationController?.pushViewController(aiChatVC, animated: true)
        } else {
            let messages = CometChatMessages()
            messages.set(user: user)
            navigationController?.pushViewController(messages, animated: true)
        }
    }
}

Styling

Customize the AI chat bubble appearance:
import UIKit
import CometChatUIKitSwift

class AIAgentStylingExample {
    
    func applyGlobalStyles() {
        // Configure AI bubble style
        let aiBubbleStyle = AiAssistantBubbleStyle()
        aiBubbleStyle.backgroundColor = .clear
        aiBubbleStyle.borderWidth = 1
        aiBubbleStyle.borderColor = .systemBlue
        aiBubbleStyle.textColor = .label
        aiBubbleStyle.textFont = UIFont.systemFont(ofSize: 14)
        aiBubbleStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 12)
        
        // Apply globally
        CometChatAiAssistantBubble.style = aiBubbleStyle
    }
    
    func applyInstanceStyles() -> ProductionAIAgentViewController {
        let aiChatVC = ProductionAIAgentViewController(user: User())
        
        // Custom message list style
        let messageListStyle = MessageListStyle()
        messageListStyle.backgroundColor = UIColor.systemBackground
        
        // Custom composer style
        let composerStyle = MessageComposerStyle()
        composerStyle.backgroundColor = UIColor.secondarySystemBackground
        composerStyle.borderColor = UIColor.separator
        composerStyle.borderWidth = 1
        
        return aiChatVC
    }
}

Style Properties

PropertyDescription
backgroundColorBubble background color
borderWidthBubble border width
borderColorBubble border color
textColorMessage text color
textFontMessage text font
cornerRadiusBubble corner radius

Customization Options

Empty State View

Customize the view shown when there are no messages:
let emptyView = UIView()
let label = UILabel()
label.text = "Start a conversation with AI"
label.textAlignment = .center
label.textColor = .secondaryLabel
emptyView.addSubview(label)

messageList.set(emptyStateView: emptyView)

Streaming Speed

Adjust how fast AI responses stream:
// Configure streaming speed (characters per second)
messageList.set(streamingSpeed: 50)

Suggested Messages

Provide quick-start prompts for users:
let suggestions = [
    "What can you help me with?",
    "Tell me about your capabilities",
    "How do I get started?"
]

messageComposer.set(suggestedMessages: suggestions)

AI Assistant Tools

Configure custom tools for the AI agent:
messageComposer.set(aiAssistantTools: { message in
    // Return custom tools based on context
    return [
        AITool(name: "search", description: "Search knowledge base"),
        AITool(name: "calculate", description: "Perform calculations")
    ]
})

Chat History Component

The CometChatAIAssistantChatHistory component displays previous AI conversations:
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class ChatHistoryViewController: UIViewController {
    
    private var user: User?
    
    convenience init(user: User) {
        self.init()
        self.user = user
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupChatHistory()
    }
    
    private func setupChatHistory() {
        guard let user = user else { return }
        
        let chatHistory = CometChatAIAssistantChatHistory()
        chatHistory.set(user: user)
        
        // New chat button
        chatHistory.set(onNewChatButtonClicked: { [weak self] in
            let newChat = ProductionAIAgentViewController(user: user)
            self?.navigationController?.pushViewController(newChat, animated: true)
        })
        
        // Resume conversation
        chatHistory.set(onMessageClicked: { [weak self] message in
            let resumeChat = ProductionAIAgentViewController(
                user: user,
                parentMessage: message,
                isHistory: true
            )
            self?.navigationController?.pushViewController(resumeChat, animated: true)
        })
        
        // Close handler
        chatHistory.set(onClose: { [weak self] in
            self?.dismiss(animated: true)
        })
        
        addChild(chatHistory)
        view.addSubview(chatHistory.view)
        chatHistory.view.frame = view.bounds
        chatHistory.didMove(toParent: self)
    }
}

Implementation Flow

StepAction
1User selects AI agent from chat list
2Detect agent by checking user role for “agentic”
3Launch ProductionAIAgentViewController
4Configure header, message list, and composer
5User sends message, AI responds with streaming
6Access chat history via header button

Components Reference

ComponentPurpose
CometChatMessageHeaderNavigation and chat history access
CometChatMessageListDisplay messages with AI responses
CometChatMessageComposerSend messages to AI agent
CometChatAIAssistantChatHistoryBrowse previous AI conversations
CometChatAiAssistantBubbleAI message bubble styling

Troubleshooting

IssueSolution
AI not respondingVerify AI features are enabled in dashboard
Chat history emptyEnsure conversations are saved properly
Streaming not workingCheck network connectivity
Styling not appliedApply styles before presenting components
Agent not detectedVerify user role contains “agentic”