Build a Hotel Finder Agent
Time: 10 minutes | What you'll build: A conversational agent that helps users find hotels in a specific city and check availability through natural conversation, with session-scoped memory so the user can refer back to earlier messages.
- Visual designer
- Ballerina code
Step 1: Create the agentic integration
- Open WSO2 Agent Builder and select Create under Start Building your Agent.
- Set Project name to
AI-Integrationsand choose a Location. - Under What do you want to build?, keep Agentic Integration selected.
- Set Agentic integration name to
HotelFinder. - Select Create Agentic Integration.


Step 2: Create the agent
The integration opens with the WSO2 Agent Builder Copilot, which asks What should your agent do? Skip it for this guide and build the agent manually.
- Under Or start from scratch, select Add Agent.


- In the Add Agent dialog, select Create Agent under Create New.


-
Set Role to
HotelFinderAssistant. -
Set Instructions to:
You are a friendly hotel finder assistant.
Your responsibilities:
- Help users find hotels and check availability through natural conversation.
- Ask clarifying questions when information is missing.
Tool usage:
- Use searchHotels when the user mentions a city or destination.
- Use checkAvailability when the user wants to verify dates and pricing.
Presentation:
- Show hotels clearly with price, rating, and key amenities.


- Keep the model as the Default WSO2 Model Provider, and leave the remaining agent settings at their defaults.
- Set Agent Name to
HotelFinderAssistant. - Select Create Agent.


By default, the agent uses the WSO2 model provider, so no third-party API key is required. Sign in to WSO2 Agent Builder if prompted.
To use a different LLM instead, see Model providers for the full list of supported providers (OpenAI, Anthropic, Azure OpenAI, and others).
The agent canvas for HotelFinderAssistant opens. The AI Agent node is connected to Default WSO2 Model Provider, with Add Trigger on its left and Add Tool at its bottom-right corner.


Step 3: Add the searchHotels tool
Create the searchHotels tool
- Select Add Tool at the bottom-right corner of the AI Agent node.
- In the Add Tool panel, select Create Custom Tool.


-
Set Name to
searchHotels. -
Set Description to
Searches for hotels in a city. -
Under Parameters, select + Add Parameter, add the following parameter, and select Add:
Type Name Description stringcityCity name, e.g. "Paris" or "New York" -
Select the Return Type field and choose Create New Type. The Create New Type dialog opens:
a. Keep Kind as
Recordand set Name toHotel.b. Select + next to Fields to add each of the following fields:
Name Type hotelIdstringnamestringcitystringpricePerNightdecimalratingfloatamenitiesstring[]c. Select Save.


- Set Return Type to
Hotel[]. - Set Description (return value) to
Hotels available in the city. - Leave Requires Approval unchecked. Enabling it pauses the tool before it runs and waits for human approval.
- Select Create Tool.
![Completed Create Custom Tool form for searchHotels showing the city parameter, Hotel[] return type, and return description](/integration-platform/docs/agent-builder/img/genai/getting-started/build-a-hotel-finder-agent-v1.0/09-create-search-hotels-tool-v1.0.png)
![Completed Create Custom Tool form for searchHotels showing the city parameter, Hotel[] return type, and return description](/integration-platform/docs/agent-builder/img/genai/getting-started/build-a-hotel-finder-agent-v1.0/09-create-search-hotels-tool-v1.0.png)
Build the searchHotels logic
The tool now appears as a node connected to the agent. Select it to open its flow. New tools open with a placeholder: Start connected to a Panic node (error("not implemented")). Replace it with the real logic:
-
Select + on the connector between Start and Panic, then select Declare Variable under Statement. Set Name to
allHotelsand Type toHotel[]. Set the Expression to the following hotel array and select Save:[
{hotelId: "HTL-001", name: "Grand Plaza Hotel", city: "Paris", pricePerNight: 199.99, rating: 4.5, amenities: ["WiFi", "Pool", "Gym"]},
{hotelId: "HTL-002", name: "City Center Inn", city: "Paris", pricePerNight: 129.99, rating: 4.0, amenities: ["WiFi", "Breakfast"]},
{hotelId: "HTL-003", name: "Luxury Suites", city: "New York", pricePerNight: 349.99, rating: 4.8, amenities: ["WiFi", "Pool", "Spa", "Restaurant"]}
]noteThis uses hardcoded sample data. In a real scenario, you would call an external hotel API, query a database, or connect an MCP tool.
![Declare Variable panel with Name set to allHotels, Type set to Hotel[], and the hotel array set as the Expression](/integration-platform/docs/agent-builder/img/genai/getting-started/build-a-hotel-finder-agent-v1.0/10-declare-variable-allhotels-v1.0.png)
![Declare Variable panel with Name set to allHotels, Type set to Hotel[], and the hotel array set as the Expression](/integration-platform/docs/agent-builder/img/genai/getting-started/build-a-hotel-finder-agent-v1.0/10-declare-variable-allhotels-v1.0.png)
-
Select + below the
allHotelsnode and select Declare Variable under Statement. Set Name tohotelsand Type toHotel[]. Set the Expression to the following and select Save:allHotels.filter(h => h.city == city)
![Declare Variable panel with Name set to hotels, Type set to Hotel[], and the filter expression set as the Expression](/integration-platform/docs/agent-builder/img/genai/getting-started/build-a-hotel-finder-agent-v1.0/11-declare-variable-hotels-v1.0.png)
![Declare Variable panel with Name set to hotels, Type set to Hotel[], and the filter expression set as the Expression](/integration-platform/docs/agent-builder/img/genai/getting-started/build-a-hotel-finder-agent-v1.0/11-declare-variable-hotels-v1.0.png)
- Select + below the
hotelsnode and select Return under Control. Set Expression tohotelsand select Save.


- The placeholder Panic node is now unreachable. Select the ⋮ menu on the Panic node and select Delete.


Step 4: Add the checkAvailability tool
Create the checkAvailability tool
-
Select the back arrow to return to the HotelFinderAssistant agent canvas.
-
Select Add Tool on the AI Agent node and choose Create Custom Tool.
-
Set Name to
checkAvailability. -
Set Description to
Checks whether a hotel has rooms available between two dates. -
Under Parameters, select + Add Parameter and add each of the following parameters:
Type Name Description stringhotelIdHotel identifier returned from searchHotels stringcheckInCheck-in date in YYYY-MM-DD format stringcheckOutCheck-out date in YYYY-MM-DD format -
Select the Return Type field and choose Create New Type. The Create New Type dialog opens:
a. Keep Kind as
Recordand set Name toAvailability.b. Select + next to Fields to add each of the following fields:
Name Type hotelIdstringhotelNamestringavailablebooleantotalPricedecimalnightsintc. Select Save.


- Make sure Return Type is set to
Availability. - Set Description (return value) to
Availability result with total price and nights. - Select Create Tool.


Build the checkAvailability logic
-
Select the checkAvailability node to open its flow.
-
Select + on the connector between Start and Panic, select Return under Control, set Expression to the following, and select Save:
{
hotelId,
hotelName: "Grand Plaza Hotel",
available: true,
totalPrice: 599.97,
nights: 3
}noteThis returns hardcoded sample data. In a real scenario, you would query a booking system, call an availability API, or connect an MCP tool.


- Select the ⋮ menu on the Panic node and select Delete.
Return to the agent canvas. The agent now shows both tools connected.


Step 5: Add a chat trigger
A trigger connects the agent to a channel that calls it. Add an Agent Chat trigger to expose the agent as a chat endpoint.
- Select Add Trigger on the left of the AI Agent node.
- Under Chat Channels, select Agent Chat.


- Keep Service Path as
/hotel-finder-assistant. - Select Create.


This creates an AI Agent Services entry point with a POST chat resource and an agentChatListener. The agent canvas now shows the Agent Chat trigger connected to the agent.


Step 6: Run and test
- Select Run Integration at the top-right corner of the editor. Wait until the terminal shows
Running executable. - Under Entry Points, expand AI Agent Services - /hotel-finder-assistant and select the
chatresource. The Chat Agent Service flow opens, showing theagent : runcall toHotelFinderAssistantand the Return node. - Select Chat to open the Agent Chat panel.
- Type
Show me hotels in Parisand send it.
The agent calls searchHotels and returns the matching Paris options (Grand Plaza Hotel and City Center Inn, not Luxury Suites, which is in New York). Continue the conversation in the same chat session to check availability.


Step 1: Define data types
Create a file named types.bal to hold the domain types:
type Hotel record {|
string hotelId;
string name;
string city;
decimal pricePerNight;
float rating;
string[] amenities;
|};
type Availability record {|
string hotelId;
string hotelName;
boolean available;
decimal totalPrice;
int nights;
|};
Step 2: Define tools and create the agent
Create a file named agents.bal. Each tool is an isolated function annotated with @ai:AgentTool. The LLM uses the summary line and + param - description lines from the Ballerina doc comment to decide when and how to call the tool. The model provider is initialized inline with ai:getDefaultModelProvider(), so no separate connections file is needed for the default WSO2 model provider.
Both tools use hardcoded sample data. In a real scenario, you would call external APIs, query a database, or connect MCP tools.
import ballerina/ai;
final ai:Agent HotelFinderAssistant = check new (
systemPrompt = {
role: string `HotelFinderAssistant`,
instructions: string `You are a friendly hotel finder assistant.
Your responsibilities:
- Help users find hotels and check availability through natural conversation.
- Ask clarifying questions when information is missing.
Tool usage:
- Use searchHotels when the user mentions a city or destination.
- Use checkAvailability when the user wants to verify dates and pricing.
Presentation:
- Show hotels clearly with price, rating, and key amenities.`
}, model = check ai:getDefaultModelProvider(), tools = [searchHotels, checkAvailability]
);
# Searches for hotels in a city
# + city - City name, e.g. "Paris" or "New York"
# + return - Hotels available in the city
@ai:AgentTool
isolated function searchHotels(string city) returns Hotel[] {
Hotel[] allHotels = [
{hotelId: "HTL-001", name: "Grand Plaza Hotel", city: "Paris", pricePerNight: 199.99, rating: 4.5, amenities: ["WiFi", "Pool", "Gym"]},
{hotelId: "HTL-002", name: "City Center Inn", city: "Paris", pricePerNight: 129.99, rating: 4.0, amenities: ["WiFi", "Breakfast"]},
{hotelId: "HTL-003", name: "Luxury Suites", city: "New York", pricePerNight: 349.99, rating: 4.8, amenities: ["WiFi", "Pool", "Spa", "Restaurant"]}
];
Hotel[] hotels = allHotels.filter(h => h.city == city);
return hotels;
}
# Checks whether a hotel has rooms available between two dates
# + hotelId - Hotel identifier returned from searchHotels
# + checkIn - Check-in date in YYYY-MM-DD format
# + checkOut - Check-out date in YYYY-MM-DD format
# + return - Availability result with total price and nights
@ai:AgentTool
isolated function checkAvailability(string hotelId, string checkIn, string checkOut) returns Availability {
return {
hotelId,
hotelName: "Grand Plaza Hotel",
available: true,
totalPrice: 599.97,
nights: 3
};
}
Step 3: Expose the agent as a chat service
Create a file named main.bal. The ai:Listener provides session-scoped chat memory. Pass the sessionId into agent.run(...) and the runtime retrieves and updates the conversation history for that session automatically.
import ballerina/ai;
import ballerina/http;
listener ai:Listener agentChatListener = new (listenOn = check http:getDefaultListener());
service /hotel\-finder\-assistant on agentChatListener {
resource function post chat(@http:Payload ai:ChatReqMessage request) returns ai:ChatRespMessage|error {
string stringResult = check HotelFinderAssistant.run(request.message, sessionId = request.sessionId);
return {message: stringResult};
}
}
Step 4: Run and test
Run the project:
bal run
Have a multi-turn conversation. Use the same sessionId across requests so the agent remembers context:
# Turn 1: search for hotels
curl -X POST http://localhost:9090/hotel-finder-assistant/chat \
-H "Content-Type: application/json" \
-d '{"sessionId": "guest-42", "message": "Show me hotels in Paris"}'
# Turn 2: refer back to an earlier result
curl -X POST http://localhost:9090/hotel-finder-assistant/chat \
-H "Content-Type: application/json" \
-d '{"sessionId": "guest-42", "message": "Can you check the City Center Inn from March 20 to March 23?"}'
Because the listener keeps session history, the agent resolves "the City Center Inn" from the earlier message without the user having to repeat themselves.
How it works
This example demonstrates two patterns you will reuse in production agents:
- Session-scoped memory:
ai:Listenerkeeps a short history of messages persessionId, so the LLM sees recent turns on every call. - Sequential tool calls: The agent calls
searchHotelsand thencheckAvailability, using each result to inform the next step. The chaining is driven entirely by the LLM's reasoning.
What's next
- Creating an agent — Full reference for agent configuration
- Tools — Advanced tool patterns, including connection-backed tools and MCP servers
- Memory — Custom memory strategies beyond the default session store