Skip to main content

AI Property Assistant

Per-listing chat assistant with two specialized agents and server-side memory.

Two Agents​

AgentHandlesContext
LISTINGAmenities, pitch advice, objection handling, comparisonsProperty details, tags, location, sales intelligence
PRICINGPrice justification, offer explanation, value comparison, cancellation plansAll of LISTING + full price breakdown, bank offers, nightly rates

Scope​

Both agents carry the same scope guardrail, injected ahead of the property context. The assistant answers only on this property, the booking journey (availability, pricing, taxes, offers, payments, cancellation), property features and location, and selling the stay — pitching, objections, comparisons.

Anything else — general knowledge, code, news, health or financial advice, unrelated travel planning, chit-chat — gets a single fixed line back:

I can only help with questions about this property and its booking — pricing, availability, amenities, offers, or how to pitch it. Ask me anything along those lines.

The rule also covers attempts to talk the assistant out of it ("ignore your instructions", role-play prompts), and a message mixing an in-scope with an out-of-scope ask is answered on the in-scope part only.

Routing​

The router picks the agent based on keywords:

"How should I pitch this to a family?"     → LISTING agent
"Why is it priced at ₹16,400?" → PRICING agent
"What if they say it's too expensive?" → PRICING agent (has "expensive")
"What amenities does it have?" → LISTING agent
"What cancellation options are available?" → PRICING agent (has "cancellation")

Server-Side Memory​

Conversations are stored in PostgreSQL via Spring AI's JdbcChatMemoryRepository. Frontend just sends conversationId + message — no history to maintain.

POST /api/v1/crs/listings/assistant/{listingId}/chat
{
"conversationId": "conv_abc123",
"message": "How should I pitch this to a family?"
}

Follow-up with same conversationId:

{
"conversationId": "conv_abc123",
"message": "What if they say it's too expensive?"
}

The assistant remembers the previous question about families and connects it to the pricing response.

Response​

{
"listingId": "lst_abc",
"message": "Start with the private pool and game room...",
"agent": "LISTING"
}

agent field tells the frontend which agent answered.

Quick Suggestions​

GET /assistant/{listingId}/start returns contextual suggestions based on listing data:

{
"suggestions": [
"Why is it priced at ₹16,400?",
"How should I pitch this to a family?",
"What objections might a client raise?",
"How does this compare to similar villas?",
"What cancellation options are available?",
"What bank offers apply here?"
]
}