Agent Skills / maison-conversations

Install this skill alone, or read it below. Raw file: SKILL.md · references/tools.md

bash
npx skills add https://docs.maison-labs.com --skill maison-conversations

Maison — Conversations and the concierge

Talk to a hotel's AI concierge, read its conversations and work the operator inbox: send a message and get the reply, fetch, list, search and export conversations, rank the most common guest questions (FAQs, topics: amenities, parking, check-in), see who holds each conversation and what needs an operator across hotels, take over or hand back, reply to the guest, whisper to the agent, stop its turn, mark read, and look up the known guest. Use to test answers after a knowledge change, to review or answer guests, to build a website FAQ, or to pull transcripts.

Part of the Maison public API. Read the maison-public-api skill first for authentication, discovery and transport details (https://docs.maison-labs.com/skills/maison-public-api/SKILL.md).

When to use

  • Verify a knowledge fix — send_message with the guest's question and read the reply.
  • Find what guests ask most (amenities, booking dates, parking, check-in) — get_common_questions.
  • Build or refresh a website FAQ from real guest questions — get_common_questions + list_knowledge_gaps, then add_qa_pairs.
  • Review recent guest conversations — list_conversations then get_conversation.
  • Find conversations by meaning — search_conversations, then get_conversation for a chosen session.
  • Hand the team a transcript export — export_chat_logs.
  • Work the operator inbox — get_conversation_attention across hotels, then list_conversation_inbox with unread or attention for one hotel.
  • Answer a guest yourself — reply_to_conversation (a reply takes the conversation over, so the agent stops replying), later set_conversation_mode with agent to hand back; the agent then answers what the guest asked meanwhile.
  • Steer the agent without the guest seeing it — whisper_to_agent; stop it with stop_conversation_turn (kind: whisper, the returned whisperId).
  • Who is this guest — get_conversation_guest, then list_guest_conversations with its guestRef. Both need guest-identity access on the hotel besides conversation access; without it they are not offered and guestName is null on list_recent_conversations.

Before you start

  1. Send x-api-key: <key> on every call; the key only reaches /api/v1.
  2. GET /api/v1/tools (or MCP tools/list) returns the tools THIS key may run — if a tool below is missing there, you lack a grant; do not retry it.
  3. Client-scoped tools take clientId (a hotel id). whoami lists the ids you can act on.

Tools

ToolWhat it doesRESTNeeds
export_chat_logsExport a hotel's conversation history as a base64-encoded XLSX workbook.GET /api/v1/client/{clientId}/conversations/exportchat-logs READ (client); plan: chat-logs; read-only
get_common_questionsWhat guests actually ask a hotel's concierge: every guest message in a date window, grouped by normalised wording and ranked by how often it was asked and in how many conversations.GET /api/v1/client/{clientId}/conversations/questionschat-logs READ (client); plan: chat-logs; read-only
get_conversationRetrieve a full chat session transcript from DynamoDB by session id.GET /api/v1/client/{clientId}/conversation/{sessionId}chat-logs READ (client); plan: chat-logs; read-only
get_conversation_attentionHow many guest conversations need an operator across the hotels you can read (or the clientIds you name): needsOperator (unread or flagged), unread, flagged, and the same per hotel in byClient.GET /api/v1/conversations/attentionchat-logs READ (any); read-only
get_conversation_guestThe known guest behind a conversation: guestRef (a guest id, or identity:<id> for a guest known only by a claimed email or phone), display name, the decrypted identities (kind and value) and how many conversations they have at the hotel.GET /api/v1/client/{clientId}/conversation/{sessionId}/guestchat-logs READ (client), guest-identity READ (client); plan: guest-identity; read-only
list_conversation_inboxOne summary per guest conversation for a hotel, newest activity first: channel, message count, first and latest message preview, topic, whether the guest is identified (guestLinked; the identity itself needs get_conversation_guest and the guest-identity grant), who holds it (agent or an operator), unread count and attention flag.GET /api/v1/client/{clientId}/conversations/inboxchat-logs READ (client); plan: chat-logs; read-only
list_conversationsReturn raw chat session rows for a client within a date window.GET /api/v1/client/{clientId}/conversationschat-logs READ (client); plan: chat-logs; read-only
list_guest_conversationsEvery conversation of one guest at a hotel, newest activity first: session id, channel, started and last activity times, message count and the first guest message (120 characters).GET /api/v1/client/{clientId}/guest/{guestRef}/conversationschat-logs READ (client), guest-identity READ (client); plan: guest-identity; read-only
list_recent_conversationsThe most recently active guest conversations across every hotel you can read conversations of (or the clientIds you name), newest first, each with its hotel id and name, preview, topic, guest name (null for a hotel where you lack guest-identity access), who holds it, unread count and attention.GET /api/v1/conversations/recentchat-logs READ (any); read-only
mark_conversation_readMark a guest conversation read: clears its unread count and attention, resolves its shared attention notice and catches up your guest-message notices.POST /api/v1/client/{clientId}/conversation/{sessionId}/readchat-logs WRITE (client); plan: chat-logs
reply_to_conversationSend a message to the guest in a conversation as yourself (an operator), delivered on the conversation's channel (web chat, WhatsApp, Instagram, Messenger, email).POST /api/v1/client/{clientId}/conversation/{sessionId}/replychat-logs EXECUTE (client); plan: chat-logs; composite of set_conversation_mode
search_conversationsFind a hotel's conversations by the meaning of guest-visible messages.GET /api/v1/client/{clientId}/conversations/searchchat-logs READ (client); plan: chat-logs; read-only
send_messageSend one message to a hotel's AI concierge (the same brain as the guest chat widget) as an operator and receive its reply.POST /api/v1/client/{clientId}/messageupdate-client READ (client)
set_conversation_modeSwitch who answers a guest conversation: operator takes it over (the agent stops replying to the guest; you reply with reply_to_conversation), agent hands it back and the agent answers whatever the guest asked while it was held.PUT /api/v1/client/{clientId}/conversation/{sessionId}/modechat-logs WRITE (client); plan: chat-logs
stop_conversation_turnStop the agent while it is working on a turn: its reply is discarded and the agent run is cancelled.POST /api/v1/client/{clientId}/conversation/{sessionId}/turn/{turnId}/stopchat-logs WRITE (client); plan: chat-logs
whisper_to_agentSend a private instruction to the agent in a guest conversation (the guest never sees it); the agent answers the guest with it in mind.POST /api/v1/client/{clientId}/conversation/{sessionId}/whisperchat-logs EXECUTE (client); plan: chat-logs

Full input fields for every tool: references/tools.md.

Recommended workflows

Build an FAQ from what guests really ask

  1. get_common_questions for the hotel (default last 30 days; raise limit, or search for a topic such as "parking") — each group has the most common phrasing, how often it was asked and in how many conversations.
  2. list_knowledge_gaps with status: "OPEN" — the questions the concierge could NOT answer, with occurrence counts. These are the highest-value FAQ entries.
  3. For each FAQ item draft the answer; check the hotel's current wording with get_conversation on a sampleSessionIds entry or list_qa_pairs with search.
  4. Publish the answers to the concierge with add_qa_pairs (knowledge skill) so the website FAQ and the chat stay consistent; answer_knowledge_gap with an answer closes a gap and creates the live Q&A pair in one call.

Test an answer end to end

  1. send_message with clientId and message; keep the returned sessionId.
  2. Send follow-ups with the same sessionId to test multi-turn behaviour.
  3. If the answer is wrong, fix it in the maison-knowledge skill and re-send in a NEW session (answers are cached per session).

Take over a conversation and hand it back

  1. get_conversation_attention (optionally clientIds) — how many conversations need an operator, per hotel.
  2. list_conversation_inbox for the hotel with attention: true or unread: true; get_conversation to read one.
  3. reply_to_conversation — while the agent is answering, records the takeover in the activity feed and pauses the agent first, then delivers your reply on the guest's channel and clears your unread count.
  4. Keep replying with reply_to_conversation; mark_conversation_read clears unread and attention without replying.
  5. set_conversation_mode with mode: "agent" hands the conversation back to the agent, which answers any guest messages left waiting.

Tips

  • send_message runs as the operator (client audience), so it may surface tools and data a guest would not see.
  • list_conversations defaults to the last 7 days; narrow with from/to and raise limit (max 500). For operator work use list_conversation_inbox, which adds who holds each conversation, unread and attention.
  • search_conversations returns session references and semantic similarity scores, not transcripts; a 503 means the separate conversations index is unavailable, not that no chats match.

Pitfalls

  • Conversations are keyed by (clientId, sessionId): a session id from one hotel is not found under another.
  • export_chat_logs returns the file inline as base64 and refuses exports over 8 MiB — narrow the date window.
  • whisper_to_agent answers 409 verified_session on a signed-in guest's web chat and 409 no_route on email conversations; take over and reply_to_conversation instead.
  • whisper_to_agent needs the agent to be answering: 409 operator_mode once the conversation is taken over (hand back first, or reply yourself), and 409 agent_unavailable when the agent could not answer on WhatsApp, Instagram or Messenger (nothing reached the guest).
  • set_conversation_mode is idempotent: asking for the current mode returns changed: false and does nothing. A takeover another operator won or already holds is 409 mode_conflict, naming who holds it.
  • A web whisper returns 202 before the agent answers; the reply appears in the transcript asynchronously.

Calling conventions

Same tool, three transports — pick whichever your runtime already speaks. Always send x-api-key.

bash
# REST
curl -X GET "https://maison-labs.com/api/v1/client/<clientId>/conversations/export" -H "x-api-key: $MAISON_API_KEY"
json
// MCP (https://maison-labs.com/mcp, Streamable HTTP): tools/call
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "export_chat_logs", "arguments": {} } }
json
// A2A (https://maison-labs.com/a2a): tasks/send with a data part
{ "jsonrpc": "2.0", "id": 1, "method": "tasks/send", "params": { "message": { "role": "user", "parts": [{ "type": "data", "data": { "tool": "export_chat_logs", "input": {} } }] } } }

Errors are the same everywhere: 401 no/invalid key; 403 forbidden with details.missing (the grants you lack — fall back to the composite's parts or stop); 403 not_entitled (the hotel's plan lacks the feature); 404, 409, 413 too_large, 503. Inputs that fail validation return 400 invalid_input with the Zod issues — fix and retry once.