Skip to main content
Use the pre:send 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 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:

Modified behavior

When you modify message.content in the pre:send event handler, the system maintains separation between processing and display:

Synchronized behavior

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

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.
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.
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.
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.
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: 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:
Apply this pattern in all use cases where you modify message_state to ensure robust and future-proof code.