Skip to main content
The Modes system allows you to define multiple picker categories (e.g., Model, Reasoning Effort, Persona) that users can configure for their chat session. This is more flexible than a single LLM picker and persists across messages.

Data Structure

ModeOption

A single selectable option within a Mode.
id
str
Unique identifier for this option (e.g., “gpt-4”, “planning”).
name
str
Display name shown in the UI (e.g., “GPT-4”, “Planning”).
description
str
Brief description shown in the dropdown.
icon
str
The lucide icon name or URL for the option. See https://lucide.dev/icons/.
default
boolean
Whether this option should be selected by default.

Mode

A category of options (e.g., “Model”, “Reasoning”).
id
str
Unique identifier for the mode (e.g., “model”).
name
str
Display name for the picker trigger.
options
List[ModeOption]
List of available options for this mode.

Set available Modes

You can define available modes using cl.context.emitter.set_modes inside the on_chat_start handler.
import chainlit as cl

@cl.on_chat_start
async def start():
    # Define a Model picker
    model_mode = cl.Mode(
        id="model",
        name="Model",
        options=[
            cl.ModeOption(id="gpt-4", name="GPT-4", icon="sparkles", default=True),
            cl.ModeOption(id="gpt-3.5", name="GPT-3.5", icon="bolt"),
        ]
    )

    # Define a Reasoning Effort picker
    reasoning_mode = cl.Mode(
        id="reasoning",
        name="Reasoning",
        options=[
            cl.ModeOption(id="high", name="High Effort", description="Think harder"),
            cl.ModeOption(id="low", name="Low Effort", description="Faster response"),
        ]
    )
    
    # Send modes to the UI
    await cl.context.emitter.set_modes([model_mode, reasoning_mode])

@cl.on_message
async def message(msg: cl.Message):
    # Access selected modes directly from the message object
    # Returns a dict of {mode_id: option_id}
    print(msg.modes) 
    # Output: {'model': 'gpt-4', 'reasoning': 'low'}
    
    selected_model = msg.modes.get("model")
    
    await cl.Message(
        content=f"Using model: {selected_model}"
    ).send()
Since version 2.9.4. If you use a SQL-based data layer, the steps table requires a modes column. See the migration guide.