Chat Conversation
AI Prompt Message
"You are a professional travel assistant. You operate in three distinct phases and must follow strict formatting rules for each.
Please make the conversation with the user, greeting and show the button according to the user request.
PHASE 1: Country Discovery
Trigger: Initial greeting.
Action: Call get_destinations.
Format: Start with [TYPE:DESTINATION], followed by a greeting, then the raw JSON […].
PHASE 2: City Discovery
Trigger: User selects a country.
Action: Call get_cities.
Format: Start with [TYPE:CITY], followed by a brief selection prompt, then the raw JSON […].
PHASE 3: Package Discovery
Trigger: User selects a city.
Action: Call tour_packages using the payload value.
Instruction To Get City ID : When the user selects a city, you will receive a message with a payload value. This payload is the term_id for that city. You must use this specific value when calling the tour_packages tool. If you do not have a term_id, ask the user to clarify their city selection
Format: Start with [TYPE:PACKAGES], followed by a brief confirmation, then the raw JSON […].
CRITICAL PROTOCOLS:
ROUTING HEADERS: Every message MUST start with [TYPE:DESTINATION], [TYPE:CITY], or [TYPE:PACKAGES].
NO SUMMARIES: Never write conversational lists or counts. Only provide the tag, a short greeting, and the raw JSON.
MACHINE READABLE: The JSON […] must be the final part of every message.
TOOL USAGE: Always use the provided tools to fetch data. Never halluncinate packages or cities."
IMPORTANT:
- Return ONLY valid JSON
- Do NOT include explanations
- Do NOT escape quotes
- Do NOT include [TYPE:…] inside JSON
- Output must be directly parseable by JSON.parse
WorkFlow
Global Parser
const rawOutput = $input.first().json.output || “”;
// =========================
// Helper: Standard return
// =========================
function formatResponse(data) {
return [{ json: data }];
}
// =========================
// Detect TYPE
// =========================
function detectType(text) {
if (text.includes(“[TYPE:DESTINATION]”)) return “DESTINATION”;
if (text.includes(“[TYPE:CITY]”)) return “CITY”;
if (text.includes(“[TYPE:PACKAGES]”)) return “PACKAGES”;
return null;
}
// =========================
// Extract CLEAN JSON
// =========================
function extractJSONArray(text) {
if (!text) return null;
// Remove TYPE tags
let cleaned = text.replace(/\[TYPE:[A-Z]+\]/g, "").trim();
// Remove placeholder
if (cleaned.includes("[...]")) return null;
// Get JSON boundaries
const start = cleaned.indexOf('[');
const end = cleaned.lastIndexOf(']');
if (start === -1 || end === -1) return null;
let jsonString = cleaned.substring(start, end + 1);
// 🔥 Fix common AI issues
jsonString = jsonString
.replace(/\\\//g, "/") // fix escaped slashes
.replace(/;\s*$/, "") // remove trailing ;
.trim();
try {
let parsed = JSON.parse(jsonString);
// Handle double-encoded JSON
if (typeof parsed === "string") {
parsed = JSON.parse(parsed);
}
return parsed;
} catch (e) {
throw new Error("JSON Parse Failed:\n" + jsonString);
}
}
// =========================
// MAIN
// =========================
const type = detectType(rawOutput);
const parsed = extractJSONArray(rawOutput);
// =========================
// DESTINATION
// =========================
if (type === “DESTINATION” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “Select a country:”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.destination,
payload: i.id
}))
}
});
}
// =========================
// CITY
// =========================
if (type === “CITY” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “Select a city:”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.city || i.name,
payload: i.id
}))
}
});
}
// =========================
// PACKAGES
// =========================
if (type === “PACKAGES” && parsed) {
const packages = parsed[0].data;
const elements = packages.map(pkg => ({
title: pkg.title,
subtitle: pkg.subtitle || "Best tour package available",
image_url: pkg.image_url,
buttons: (pkg.buttons || []).map(btn => ({
type: btn.type === "web_url" ? "web_url" : "postback",
title: btn.title,
url: btn.url,
payload: btn.payload
}))
}));
return formatResponse({
recipient: { id: "123456" },
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: elements
}
}
}
});
}
// =========================
// FALLBACK
// =========================
return formatResponse({
message: {
text: rawOutput || “No response available.”
}
});
My Questions
- I would like to have the conversation as well and the AI Agent will search for itself and give.
- Currently it is only work according to the button click and payload.
- After the program details click by the user, the AI will fetch the data only for that package and make the conversation. .
To Make all of the work , please suggest me how to make the workflow and how to make the system design, and how many AI Agent do i need to use and how to tell the workflow that which tool to use when needed ?
Please Help me to brainstorming or help to guide me , thank you.



