How To Make The Work Flow Like Below

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.

Okay, after reading your posts, here is my feedback after considering the requirements, I hope this helps.

Objective and approach

  • Build a modular, self-learning conversational flow that can fetch data beyond predefined button payloads.

  • Use a small set of specialized AI agents (or tools) to cover discovery, selection, packaging, and narrative conversation.

  • Orchestrate tool usage declaratively in the workflow, so the system chooses the right tool at the right time.


System design overview

  • Primary components

    1. Chat Orchestrator (n8n or a microservice): drives the conversation state, routing to agents/tools.

    2. AI Agent Layer: a small set of specialized agents (Discovery, City, Packages, Narrative) with bounded scopes.

    3. Data & Tools: get_destinations, get_cities, tour_packages, and any external data sources. All accessed via stable APIs.

    4. State & Context Store: stores user session data, chosen country/city, and selected package, plus IDs for traceability.

    5. Message Formatter: enforces the [TYPE:DESTINATION]/[TYPE:CITY]/[TYPE:PACKAGES] routing headers and final JSON payload.

    6. Observability: structured logs, tracing IDs, and error dashboards.

  • Data flow pattern

    1. User greets → Discovery agent provides destinations.

    2. User selects a destination → City agent provides cities for that country.

    3. User selects a city → Packages agent fetches packages; conversation continues with package detail.

    4. Upon package selection, system fetches detailed package data and updates conversation with rich content.


AI agent design & roles

  • Agent A: Discovery

    • Purpose: fetch and present destinations; keep JSON payload as the single source of truth.

    • Output: [TYPE:DESTINATION] header + greeting + raw JSON.

  • Agent B: City

    • Purpose: fetch cities for a chosen destination; provide concise prompts to select a city.

    • Output: [TYPE:CITY] header + brief prompt + raw JSON.

  • Agent C: Packages

    • Purpose: fetch packages for a city when a city is selected; provide compact, skimmable details.

    • Output: [TYPE:PACKAGES] header + brief confirmation + raw JSON.

  • Agent D: Narrative/Conversation

    • Purpose: generate human-like dialogue that references the chosen destination/city/package and guides the user.

    • Output: natural language messages guided by the current context, while still emitting the required TYPE header when needed.

  • Agent E: Verification & Safety

    • Purpose: ensure data accuracy, prevent hallucinations, enforce data privacy, and validate payload integrity across all steps.
  • Optional: Data Enrichment Agent

    • Purpose: fetch additional metadata (seasonality, weather, local tips) to enrich package descriptions.
  • Start with 4 core agents (Discovery, City, Packages, Narrative) plus a light Verification agent. You can add enrichment later.

How the workflow decides which tool/agent to use

  • Implement a routing layer in the Orchestrator:

    • If no TYPE present or initial greeting → Discovery.

    • If user selected a country → City.

    • If user selected a city → Packages.

    • If user asks for narrative or deeper detail → Narrative.

    • If data integrity or sensitive data is involved → Verification.

  • Use explicit state transitions:

    • state: { phase: “discovery” | “city” | “packages” | “narrative”, country_id, city_id, package_id, user_id }
  • Define a centralized tool registry with:

    • name, type (API call, local function, LLM), input schema, output schema, error policy.

Conversation schema & formatting

  • Maintain the required routing header in every message:

    • [TYPE:DESTINATION]

    • [TYPE:CITY]

    • [TYPE:PACKAGES]

  • Ensure final machine-readable JSON payload is the last block of the message.

  • Conversation flow example (high level)

    1. Discovery:

      • Output: [TYPE:DESTINATION] + greeting + raw JSON destinations
    2. City:

      • Output: [TYPE:CITY] + prompt + raw JSON cities
    3. Packages:

      • Output: [TYPE:PACKAGES] + confirmation + raw JSON packages
    4. Narrative:

      • Output: natural language messages with context, or a detailed package narrative, still tagged when required.
  • Persistence and traceability

    • Attach a session_id and a request_id to every message to correlate steps.

Workflow orchestration blueprint (n8n-oriented)

  • Nodes layout (modular blocks)

    1. Trigger: HTTP or Chat webhook to start a session.

    2. State Loader: load session context from a datastore.

    3. AI Gateway: select appropriate agent based on phase.

    4. Agent Call: invoke get_destinations / get_cities / tour_packages or narrative content.

    5. Response Formatter: wrap in the correct [TYPE:*] header and final JSON.

    6. State Saver: persist updated context and selections.

    7. Output: send to user, log the interaction.

  • Data contracts

    • Destinations API returns: [{ id, country, name, description, image }, …]

    • Cities API returns: [{ id, city, country_id, region }, …]

    • Packages API returns: [{ id, title, summary, image_url, price, details }, …]

  • Error handling

    • Retry policy with exponential backoff for transient API errors.

    • Fallback messages if APIs fail, with a clear trace ID.

    • Validation at each step to ensure required fields exist before proceeding.

  • Security & isolation

    • Each container uses a dedicated network and an API key scoped to the agent.

    • Secrets managed by a vault; rotate periodically.

    • Least-privilege in Docker Compose or Kubernetes manifests