Skip to main content

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.

Triggered before chat receives a response from the agent. Use this event to inspect or modify the agent’s response before it is rendered in the UI.

Event properties

type
string
required
Always 'pre:receive'.
message
object
required
The agent’s response payload.
message.content
array
required
Array of content items in the response.
message.content[].text
string
Text content of the response item. If you need to modify the displayed text only, update this property.
message.content[].response_type
string
Type of the response item, for example, 'text', 'user_defined'.
message.message_state
object
State information for the message. You can create a new object with the spread operator before adding nested custom properties.
message.message_state.user_defined
object
A dedicated namespace for your custom metadata. Use this namespace to:
  • Prevent conflicts with system properties.
  • Keep your custom data organized.
  • Ensure future platform updates do not break your code.
To use this namespace, create a new message_state object and a new user_defined object inside it. Add your custom properties inside user_defined.
If message_state or user_defined was previously sealed or made non-extensible, directly assigning a new nested property can throw an Object is not extensible error in strict mode. To make your code more robust and preserve existing properties, use the spread operator to create a fresh object reference before adding custom fields:
event.message.message_state = {
  ...event.message.message_state,
  user_defined: {
    ...(event.message.message_state?.user_defined || {}),
    my_custom_flag: true
  }
};
saveUpdate
boolean
Set to true to persist client-side modifications to the backend database.When you modify message content in pre:receive, those changes only affect what displays in the UI. This triggers an automatic PATCH API call that persists your changes.
The system does not automatically set tracking properties. If you need to track whether modifications were applied, create a new message_state object and set the flag inside message_state.user_defined before enabling saveUpdate.

Examples

The following example demonstrates how to modify agent response text and add custom feedback controls before displaying the message to the user:
instance.on('pre:receive', (event, instance) => {
    // Log the incoming message for debugging purposes
    console.log('About to receive message:', event.message);
    
    // Modify response text by replacing specific words
    // This iterates through all content elements in the response
    event?.message?.content?.forEach((element) => {
        if (element?.text?.includes('assistant')) {
            // Replace 'assistant' with 'Agent' for brand consistency
            element.text = element.text.replace('assistant', 'Agent');
        }
    });
    
    // Add feedback controls to the last item in the response
    // This allows users to provide feedback on the agent's response
    const lastItem = event?.message?.content?.[event.message.content.length - 1];
    if (lastItem) {
        lastItem.message_options = {
            feedback: {
                is_on: true, // Enable feedback controls
                show_positive_details: false, // Hide details form for positive feedback
                show_negative_details: true, // Show details form for negative feedback
                positive_options: {
                    categories: ['Helpful', 'Accurate', 'Clear'],
                    disclaimer: "Your feedback helps us improve."
                },
                negative_options: {
                    categories: ['Inaccurate', 'Incomplete', 'Confusing', 'Other'],
                    disclaimer: "Please provide details to help us improve."
                }
            }
        };
    }
});
The following example demonstrates how to translate agent responses from English to the user’s preferred language before displaying them in the UI:
instance.on('pre:receive', async (event, instance) => {
    // Define the user's preferred language (could be dynamic based on user settings)
    const userLanguage = 'es'; // User's preferred language
    
    // Only translate if the user's language is not English
    if (userLanguage !== 'en' && event?.message?.content) {
        // Translate each text content item in the response
        // Agent responses can contain multiple content items
        for (const content of event.message.content) {
            if (content.response_type === 'text' && content.text) {
                // Translate from English to user's language
                // Note: translateText() is a placeholder - implement your own translation service
                const translatedText = await translateText(content.text, 'en', userLanguage);
                
                // Update the text that will be displayed in the UI
                content.text = translatedText;
            }
        }
        
        // Store custom metadata in user_defined namespace
        // Use the spread operator to preserve existing properties and avoid
        // issues with sealed or non-extensible objects in strict mode
        event.message.message_state = {
            ...event.message.message_state,
            user_defined: {
                ...(event.message.message_state?.user_defined || {}),
                translated_language: userLanguage
            }
        };
    } else {
        // Mark as English (no translation needed)
        event.message.message_state = {
            ...event.message.message_state,
            user_defined: {
                ...(event.message.message_state?.user_defined || {}),
                translated_language: 'en'
            }
        };
    }
    
    // Trigger automatic persistence to save the translated message
    // This makes a PATCH API call to update the message in the database
    event.saveUpdate = true;
});
The following example demonstrates how to translate with streaming suppression. When using translation with streaming responses, suppress delta rendering in pre:stream:delta:
// Suppress streaming deltas during translation
instance.on('pre:stream:delta', (event, instance) => {
    const userLanguage = 'es';
    
    if (userLanguage !== 'en') {
        // Suppress character-by-character rendering
        event.delta.content = [];
    }
});

// Translate complete message
instance.on('pre:receive', async (event, instance) => {
    const userLanguage = 'es';
    
    if (userLanguage !== 'en' && event?.message?.content) {
        for (const content of event.message.content) {
            if (content.response_type === 'text' && content.text) {
                content.text = await translateText(content.text, 'en', userLanguage);
            }
        }
        // Store custom metadata in user_defined namespace
        event.message.message_state = {
            ...event.message.message_state,
            user_defined: {
                ...(event.message.message_state?.user_defined || {}),
                translated_language: userLanguage
            }
        };
    } else {
        event.message.message_state = {
            ...event.message.message_state,
            user_defined: {
                ...(event.message.message_state?.user_defined || {}),
                translated_language: 'en'
            }
        };
    }
    
    event.saveUpdate = true;
});

Considerations

Persistence across sessions

Modifications made in pre:receive might not run in all scenarios, for example:
  • Users might close browser before response arrives.
  • Users navigate away during response.
  • Long-running flows return responses hours later.
To address persistence across sessions, you can implement the same logic in both events:
  1. Use pre:receive for new messages.
  2. Use pre:threadLoaded for historical messages.
  3. Add a tracking flag in message_state.user_defined to avoid duplicate processing.
Example tracking flag: message_state.user_defined.already_processed = true

Do you need practical examples?

Learn how to apply the features available for embedded chat into your implementation with guidance and examples.