> ## Documentation Index
> Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling user input with pre:send event

Use the [`pre:send`](preSend) event to intercept and modify user messages before they are sent to the agent. This capability enables powerful use cases such as message translation, input sanitization, content transformation, and adding contextual metadata.

## Understanding the message content system

When working with user input in the [`pre:send`](preSend) event, two properties control different aspects of the message:

### message.content

The `message.content` property contains the text that is sent to the agent for LLM processing. When you modify this property:

* The agent receives the modified text for generating responses.
* The modification affects what the LLM processes and how it responds.
* The original user input is preserved in the chat UI by default.

### message\_state.input.display\_text

The `message_state.input.display_text` property contains the text that is displayed in the chat UI. When present:

* This property takes priority over `message.content` for display purposes.
* The user sees this text in their chat.
* This allows you to show different text than what the agent receives.

## How the system works

### Default behavior

By default, when a user types a message, the system uses the same text for both LLM processing and UI display:

```javascript theme={null}
// User types: "Hello, how are you?"
// System automatically sets:
{
  message: {
    content: "Hello, how are you?",
    message_state: {
      input: {
        display_text: undefined  // Not set, so content is used for display
      }
    }
  }
}
```

### Modified behavior

When you modify `message.content` in the [`pre:send`](preSend) event handler, the system maintains separation between processing and display:

```javascript theme={null}
instance.on('pre:send', (event, instance) => {
    // Modify content for agent
    event.message.message.content = "HELLO, HOW ARE YOU?";
    
    // display_text isn't set, so UI shows original: "Hello, how are you?"
});
```

### Synchronized behavior

To synchronize what the agent receives with what the user sees, update both properties:

```javascript theme={null}
instance.on('pre:send', (event, instance) => {
    const modified = "HELLO, HOW ARE YOU?";
    
    // Update for agent processing
    event.message.message.content = modified;
    
    // Update for UI display
    event.message.message.message_state = {
        input: { display_text: modified }
    };
    
    // Now both agent and user see: "HELLO, HOW ARE YOU?"
});
```

## Common use cases

### Use case 1: Message translation

In multilingual applications, you might need to translate user messages to a common language that your agent understands while preserving the original language in the chat interface. For example, if a Spanish-speaking user types "Hola, ¿cómo estás?" but your agent only processes English, you can translate the message for the agent while showing the user their original Spanish text.

This pattern works by updating only `message.content` with the translated text for agent processing, while setting `message_state.input.display_text` to preserve the original language in the UI.

```javascript [expandable] theme={null}
instance.on('pre:send', async (event, instance) => {
    const userLanguage = 'es';
    
    if (userLanguage !== 'en' && event?.message?.message?.content) {
        // Store the original text
        const originalText = event.message.message.content;
        
        // Translate to English for agent processing
        const translatedText = await translateToEnglish(originalText);
        
        // Agent receives English translation
        event.message.message.content = translatedText;
        
        // User sees their original Spanish input
        // Note: display_text is set to preserve the original language in UI
        event.message.message.message_state = {
            input: { display_text: originalText }
        };
    }
});
```

In this example, the agent receives "Hello, how are you?" for processing, while the user sees their original message "Hola, ¿cómo estás?" in the chat interface. This approach enhances agent understanding without changing the user experience.

### Use case 2: Input sanitization

Protecting sensitive information is critical in chat applications. You can automatically detect and remove sensitive data like credit card numbers, social security numbers, or passwords before sending messages to the agent, while still showing users what they typed. This maintains transparency with users while protecting their data.

For instance, if a user accidentally includes a credit card number in their message, you can mask it before the agent processes it. Update only `message.content` with the sanitized version while preserving the original input in `message_state.input.display_text`.

```javascript [expandable] theme={null}
instance.on('pre:send', (event, instance) => {
    const userInput = event.message.message.content;
    
    // Detect and mask credit card numbers
    const creditCardPattern = /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g;
    const sanitizedContent = userInput.replace(creditCardPattern, '[CARD NUMBER REDACTED]');
    
    // Agent receives sanitized version
    event.message.message.content = sanitizedContent;
    
    // User sees their original input
    // Note: Preserving original input maintains transparency with the user
    event.message.message.message_state = {
        input: { display_text: userInput }
    };
});
```

The agent receives "I want to pay with \[CARD NUMBER REDACTED]" while the user sees their original message "I want to pay with 1234 5678 9012 3456" in the chat. Always preserve the original user input in the UI when sanitizing data to maintain transparency and allow users to see exactly what they typed.

### Use case 3: Content transformation

Sometimes you need to transform user input into a standardized format that your agent can process more effectively. This is useful when you want to normalize casual language into formal system messages or convert user queries into structured commands. Unlike the previous patterns, this approach updates both `message.content` and `message_state.input.display_text` so that users see the transformed version of their input.

For example, you might convert casual greetings like "hello" or "hi" into formal system messages such as "User initiated greeting protocol." This provides clear feedback to users about how their input is being interpreted.

```javascript [expandable] theme={null}
instance.on('pre:send', (event, instance) => {
    const userInput = event.message.message.content;
    let processedContent;
    
    // Transform casual greetings
    if (userInput.toLowerCase().includes('hello') ||
        userInput.toLowerCase().includes('hi')) {
        processedContent = "User initiated greeting protocol";
    } else if (userInput.toLowerCase().includes('bye')) {
        processedContent = "User initiated farewell protocol";
    } else {
        processedContent = `User query: ${userInput}`;
    }
    
    // Both agent and user see the transformed version
    event.message.message.content = processedContent;
    event.message.message.message_state = {
        input: { display_text: processedContent }
    };
});
```

Both the agent and user see "User initiated greeting protocol" in this case. Use this pattern when you want to provide feedback about input transformation or replace user input with a standardized message format.

### Use case 4: Adding context

Agents often provide better responses when they have additional context about the user and their session. You can enrich messages with metadata like user IDs, session duration, authentication status, or previous interaction history without cluttering the user interface. This keeps the chat clean and focused for users while giving the agent the information it needs to provide personalized, context-aware responses.

For example, you might include user metadata and session information in the message sent to the agent. Update only `message.content` with the enriched information while keeping `message_state.input.display_text` set to the original user message.

```javascript [expandable] theme={null}
instance.on('pre:send', (event, instance) => {
    const userInput = event.message.message.content;
    const userId = getCurrentUserId();
    const sessionTime = getSessionDuration();
    
    // Add context for agent
    const enrichedContent = `[User: ${userId}, Session: ${sessionTime}min] ${userInput}`;
    event.message.message.content = enrichedContent;
    
    // User sees only their original message
    // Note: Not setting display_text keeps the UI clean and focused
    event.message.message.message_state = {
        input: { display_text: userInput }
    };
    
    // Add metadata for additional tracking
    event.message.metadata = {
        userId: userId,
        sessionDuration: sessionTime,
        timestamp: Date.now()
    };
});
```

The agent receives "\[User: user123, Session: 5min] What are your hours?" with all the contextual information, while the user simply sees "What are your hours?" in their chat interface. This approach keeps the user interface clean by hiding technical metadata from users while providing rich context to the agent for better responses.

## Message flow diagram

Understanding the complete message flow helps you determine where to make modifications:

```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#0f62fe','primaryTextColor':'#fff','primaryBorderColor':'#0043ce','lineColor':'#525252','secondaryColor':'#393939','tertiaryColor':'#161616','background':'#f4f4f4','mainBkg':'#ffffff','secondaryBkg':'#e0e0e0','tertiaryBkg':'#c6c6c6','textColor':'#161616','fontSize':'14px'}}}%%
flowchart TD
    A[User types message] --> B[pre:send event fires]
    B --> C{Event handler<br/>executes}
    
    C -->|Modify| D[message.content<br/>for agent]
    C -->|Optional| E[message_state.input.display_text<br/>for UI]
    
    D --> F[Message sent to agent]
    F --> G[Agent receives<br/>message.content]
    
    E --> H{display_text set?}
    H -->|Yes| I[UI shows<br/>display_text]
    H -->|No| J[UI shows<br/>message.content]
    
    I --> K[Message displayed<br/>in chat UI]
    J --> K
    
    G --> L[Agent processes<br/>and responds]
    
    style A fill:#0f62fe,stroke:#0043ce,stroke-width:2px,color:#fff
    style B fill:#0f62fe,stroke:#0043ce,stroke-width:2px,color:#fff
    style C fill:#393939,stroke:#161616,stroke-width:2px,color:#fff
    style D fill:#0f62fe,stroke:#0043ce,stroke-width:2px,color:#fff
    style E fill:#0f62fe,stroke:#0043ce,stroke-width:2px,color:#fff
    style F fill:#0f62fe,stroke:#0043ce,stroke-width:2px,color:#fff
    style G fill:#8a3ffc,stroke:#6929c4,stroke-width:2px,color:#fff
    style H fill:#393939,stroke:#161616,stroke-width:2px,color:#fff
    style I fill:#8a3ffc,stroke:#6929c4,stroke-width:2px,color:#fff
    style J fill:#8a3ffc,stroke:#6929c4,stroke-width:2px,color:#fff
    style K fill:#8a3ffc,stroke:#6929c4,stroke-width:2px,color:#fff
    style L fill:#8a3ffc,stroke:#6929c4,stroke-width:2px,color:#fff
```

Legend:

* Blue nodes: User actions, event triggers, and modifiable properties
* Gray nodes: Decision points in your code
* Purple nodes: Agent processing and UI display logic

## Preserving existing message state

When modifying `message_state`, use the spread operator to preserve existing properties and avoid errors. You can implement this practice to have the following implementation:

* The `message_state` object might already contain properties set by the chat framework or other event handlers. If you directly assign a new object without spreading the existing properties, you lose these values, which can break functionality that depends on them. The spread operator (`...`) preserves all existing properties while adding or updating only the ones you specify.

* JavaScript objects can be sealed or frozen to prevent modifications. When you try to directly assign a new object to a sealed property, JavaScript throws an error. By using the spread operator to merge properties instead of replacing the entire object, you work within the constraints of the object's extensibility settings and avoid runtime errors.

* The chat platform evolves over time, and future updates might introduce new properties to `message_state` that your code doesn't know about yet. By preserving existing properties with the spread operator, your code remains compatible with both current and future versions of the platform, reducing the risk of breaking changes when you upgrade.

The following example shows how to implement this pattern:

```javascript [expandable] theme={null}
instance.on('pre:send', (event, instance) => {
    // Safely merge new properties with existing state
    event.message.message.message_state = {
        ...event.message.message.message_state,
        input: {
            ...(event.message.message.message_state?.input || {}),
            display_text: "Your text here"
        }
    };
});
```

Apply this pattern in all use cases where you modify `message_state` to ensure robust and future-proof code.

## Related events

* [`pre:receive`](preReceive)
* [`pre:threadLoaded`](preThreadLoaded)
