Example: Customizing User Interface Using Custom Lightning Types with Top-Level Collection Renderer Override

This example explains how to override the default user interface to create a customized appearance of responses on the custom agent’s action output with custom Lightning types.

In this example, you specify a renderer collection override for the custom Lighting type that you created.

Before You Begin 

Download these sample data files.

Example Apex Class for Retrieving Hotel Information 

Use these Apex classes together to create a custom agent action that finds available hotels. The main HotelReservation class contains the invocable method, and the other classes define the complex data structures for the request and response.

When you create your custom agent action, select the method Find hotels.

HotelReservation Class

This class is the main class that contains the logic for the find hotels agent action.

1@JsonAccess(serializable='always' deserializable='always')
2global class HotelReservation {
3    @InvocableMethod(label='Find hotels ' description='Find Available Hotels')
4    global static List<HotelResponse> findHotels(List<HotelRequest> req) {
5        // For example, we hardcode the data and don’t focus on how we retrieve it.
6        // However, consider that we receive available hotel data from a service
7        // and then iterate through the data to generate the final response.
8
9        List<HotelResponse> hotelResponseList = new List<HotelResponse>();
10
11        Room r1 = new Room('DELUX', 2, 15.15d, 2000l, false);
12        List<Room> rooms = new List<Room>();
13        rooms.add(r1);
14
15        HotelCategory fourStar = new HotelCategory('four');
16        Hotel hotel1 = new Hotel('Sahara Hotels', 'Gacchibowli Hyderabad', rooms, fourStar);
17        HotelCategory fiveStar = new HotelCategory('five');
18        Hotel hotel2 = new Hotel('Taj Vivanta', 'Kokapet', rooms, fiveStar);
19        List<Hotel> hotels = new List<Hotel>();
20        hotels.add(hotel1);
21        hotels.add(hotel2);
22
23        HotelResponse hotelresponse = new HotelResponse(hotels);
24        hotelResponseList.add(hotelresponse);
25
26        return hotelResponseList;
27    }
28}

HotelResponse Class

This class defines the data structure for the response that returns a list of available hotels.

1@JsonAccess(serializable='always' deserializable='always')
2global class HotelResponse {
3    @InvocableVariable
4    global List<Hotel> hotels;
5
6    global HotelResponse(List<Hotel> hotels) {
7        this.hotels = hotels;
8    }
9}

Hotel Class

This class defines the data structure for hotel details.

1@JsonAccess(serializable='always' deserializable='always')
2global class Hotel {
3    @InvocableVariable
4    global String name;
5
6    @InvocableVariable
7    global String address;
8
9    @InvocableVariable
10    global List<Room> rooms;
11
12    @InvocableVariable
13    global HotelCategory hotelCategory;
14
15    global Hotel(String name, String address, List<Room> rooms, HotelCategory hotelCategory) {
16        this.name = name;
17        this.address = address;
18        this.rooms = rooms;
19        this.hotelCategory = hotelCategory;
20    }
21}

Room Class

This class defines the data structure for rooms within a hotel.

1@JsonAccess(serializable='always' deserializable='always')
2global class Room {
3    @InvocableVariable
4    global String type;
5
6    @InvocableVariable
7    global Integer available;
8
9    @InvocableVariable
10    global Double discountPercentage;
11
12    @InvocableVariable
13    global Long price;
14
15    @InvocableVariable
16    global Boolean petAllowed;
17
18    global Room(String type, Integer available, Double discountPercentage, Long price, Boolean petAllowed) {
19        this.type = type;
20        this.available = available;
21        this.discountPercentage = discountPercentage;
22        this.price = price;
23        this.petAllowed = petAllowed;
24    }
25}

HotelCategory Class

This class defines the data structure for a hotel’s star rating.

1@JsonAccess(serializable='always' deserializable='always')
2global class HotelCategory {
3    @InvocableVariable
4    global String star;
5
6    global HotelCategory(String star) {
7        this.star = star;
8    }
9}

HotelRequest Class

This class defines the data structure for the agent action’s input criteria.

1@JsonAccess(serializable='always' deserializable='always')
2global class HotelRequest {
3    @InvocableVariable
4    global String city;
5
6    @InvocableVariable
7    global Date checkInDate;
8
9    @InvocableVariable
10    global Date checkOutDate;
11}

The Apex class Hotel Reservation accepts the hotel search criteria, including the check in date, check out date, and city, and then returns a list of available hotels.

For this example, hotel availability data is already included in the Hotel Reservation Apex class. However, in a real-time scenario, hotel information is fetched from an external service, and the Apex class processes that data to generate the final response.

Note

Create Agent Action by Using Apex Class 

For information about how to create a custom action by using Apex class, see Create a Custom Agent Action.

Inputs and outputs for the agent action are defined by using standard Lightning types.

Input:

  • checkInDate, checkOutDate, and city use standard Lightning types such as lightning__dateType and lightning__textType.

Output:

  • The output hotels for the agent action is a list type.

Here’s an image that shows the custom agent action created.

Input and output settings for a 'Find hotels' agent action. Inputs: checkInDate, checkOutDate, City. Output: hotels.

The available flight information is retrieved by using @apexClassType/c__Hotel in the agent action output, where:

  • apexClassType is the bundle name.
  • Hotel is the Apex class.

When you execute this agent action, it prompts you to provide input and then generates the output.

Agent Action Execution Input 

The agent’s action UI collects these details to find available hotels.

  • Check in date
  • Check out date
  • City

Here’s the image that shows how the custom agent action input appears in an agent conversation.

Agent action input collects hotel details: checkInDate, checkOutDate, and city.

Agent Action Execution Output 

The agent’s action UI returns the available hotel details.

Here’s the image that shows how the custom agent action’s output appears in an agent conversation.

Agent's response to a hotel details request. The response lacks labels and is presented in a format that is hard to understand.

Result Data 

The agent displays the hotel data in the response.

Here’s the sample code that shows the available hotel data.

1{
2  "hotels": [
3    {
4      "rooms": [
5        {
6          "type": "DELUX",
7          "price": 2000,
8          "petAllowed": false,
9          "discountPercentage": 15.15,
10          "available": 2
11        }
12      ],
13      "name": "Sahara Hotels",
14      "hotelCategory": {
15        "star": "four"
16      },
17      "address": "Gacchibowli Hyderabad"
18    },
19    {
20      "rooms": [
21        {
22          "type": "DELUX",
23          "price": 2000,
24          "petAllowed": false,
25          "discountPercentage": 15.15,
26          "available": 2
27        }
28      ],
29      "name": "Taj Vivanta",
30      "hotelCategory": {
31        "star": "five"
32      },
33      "address": "Kokapet"
34    }
35  ]
36}

Customize UI for Output 

Create a custom Lightning type named hotelResponse to enhance the visibility of the information in the output UI.

Override Default UI for Output With Custom Lightning Types 

Override the agent’s action UI for output to enhance the user experience by using Custom Lightning Types (CLTs). With CLTs, you can add your own Lightning Web Components (LWC) to present data for lists in a more structured and intuitive format.

Configure the renderer.json file to override the default UI of a custom Lightning type in the agent action.

Here’s an example showing a lightningTypes folder for a custom Lightning type named hotelResponse.

1+--lightningTypes
2        +--hotelResponse
3            +--schema.json
4            +--lightningDesktopGenAi
5               +--renderer.json

This example uses lightningDesktopGenAi to configure the custom Lightning type. To configure the type for the enhancedWebChat channel, create the renderer.json file in the corresponding channel folder.

Note

The custom Lightning type hotelResponse includes a schema.json file and a renderer.json file. The renderer.json file controls how the data is displayed to the user in the agent action output.

This sample code shows the contents of the schema.json file.

1{
2  "title": "Hotel Reservation",
3  "description": "Hotel Reservation",
4  "lightning:type": "@apexClassType/c__Hotel"
5}

This sample code shows the contents of the renderer.json file.

1{
2  "collection": {
3    "renderer": {
4      "componentOverrides": {
5        "$": {
6          "definition": "c/hotelDetails"
7        }
8      }
9    }
10  }
11}

Build Output Components with Lightning Web Components 

This section explains how the components are created and deployed for agent action output.

This image shows the Lightning Web Component (LWC) folder structure.

The lwc folder contains a folder named hotelDetails, which is the LWC component. The hotelDetails folder includes CSS, HTML, JS, and metadata files.

The LWC component includes HTML markup designed to accept output for @apexClassType/c__Hotel. This HTML markup ensures that the data is displayed in an intuitive and customized format.

This sample code shows the contents of the hotelDetails.js-meta.xml file.

1<?xml version="1.0" encoding="UTF-8"?>
2<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
3    <apiVersion>64.0</apiVersion>
4    <isExposed>true</isExposed>
5    <masterLabel>HotelDetails</masterLabel>
6  <targets>
7        <target>lightning__AgentforceOutput</target>
8    </targets>
9    <targetConfigs>
10        <targetConfig targets="lightning__AgentforceOutput">
11            <sourceType name="lightning__listType" itemTypeName="c__hotelResponse"/>
12        </targetConfig>
13    </targetConfigs>
14</LightningComponentBundle>

When you create an LWC component to override the UI for action input, use lightning__AgentforceInput as the target. For output, use lightning__AgentforceOutput. For information about LWC target types, see lightning__AgentforceInput Target and lightning__AgentforceOutput Target.

Note

This sample code shows the contents of the hotelDetails.html file.

1<template>
2  <lightning-card title="Available Hotels" icon-name="standard:travel_mode">
3    <template if:true="{value}">
4      <div class="slds-p-around_medium">
5        <template for:each="{value}" for:item="hotel">
6          <div key="{hotel.name}" class="hotel-card slds-box slds-box_x-small slds-m-bottom_large">
7            <div class="slds-grid slds-grid_align-spread slds-m-bottom_small">
8              <div>
9                <h2 class="slds-text-heading_medium slds-truncate hotel-name">{hotel.name}</h2>
10                <div class="slds-text-body_small slds-m-top_xx-small slds-text-color_weak">
11                  <lightning-icon
12                    icon-name="utility:location"
13                    size="xx-small"
14                    class="slds-m-right_xx-small"
15                  ></lightning-icon>
16                  {hotel.address}
17                </div>
18              </div>
19            </div>
20
21            <div class="slds-grid slds-wrap slds-m-bottom_small">
22              <template for:each="{hotel.rooms}" for:item="room">
23                <div
24                  key="{room.type}"
25                  class="slds-box slds-box_xx-small slds-theme_shade slds-m-bottom_medium slds-size_1-of-1 room-box"
26                >
27                  <div class="slds-grid slds-grid_align-spread slds-m-bottom_x-small">
28                    <div>
29                      <p class="slds-text-title_bold">{room.type}</p>
30                      <p class="slds-text-body_small">
31                        <lightning-icon
32                          icon-name="utility:event"
33                          size="xx-small"
34                          class="slds-m-right_xx-small"
35                        ></lightning-icon>
36                        Available: {room.available}
37                      </p>
38                      <p class="slds-text-body_small">
39                        <lightning-icon
40                          icon-name="utility:animal_and_nature"
41                          size="xx-small"
42                          class="slds-m-right_xx-small"
43                        ></lightning-icon>
44                        Pets Allowed: {room.petAllowed}
45                      </p>
46                    </div>
47                    <div class="slds-text-align_right">
48                      <div class="price-tag">₹{room.price}</div>
49                      <div class="discount-chip">{room.discountPercentage}% Off</div>
50                    </div>
51                  </div>
52                </div>
53              </template>
54            </div>
55          </div>
56        </template>
57      </div>
58    </template>
59  </lightning-card>
60</template>

This sample code shows the contents of the hotelDetails.js file.

1import { LightningElement, api } from "lwc";
2
3export default class HotelDetails extends LightningElement {
4  @api value;
5}

See Also

Integrate Custom Lightning Type into Agent Action Output 

To add a custom Lightning type to the agent action, complete these steps.

  1. Open the agent action.
  2. Edit the Output Rendering parameter of the agent action output for HotelResponse.
  3. Select the custom lightning type HotelResponse.
  4. Save the agent action.

The Unsupported Data Type message appears in the Map to Variable parameter. You see this message when you refer to types such as @apexClassType and custom Lightning types in an agent action’s Output Rendering parameter. This message doesn’t affect your saved work and can be safely ignored.

This image shows the custom Lightning type that you created.

The agent action output settings with 'hotelResponse' selected in the Output Rendering field.

Customized Input UI 

Before executing the agent action that you modified, reload the agent page. The agent prompts you to provide input and then generate the output. The output provides a new UI experience.

This image shows how the custom agent action’s input appears in an agent conversation.

Agent's response to a hotel details request. The response includes clear labels and is presented in a format that is easy to understand.