Agent Skills / maison-conversations
Install this skill alone, or read it below. Raw file: SKILL.md · references/tools.md
npx skills add https://docs.maison-labs.com --skill maison-conversationsMaison — 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_messagewith 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, thenadd_qa_pairs. - Review recent guest conversations —
list_conversationsthenget_conversation. - Find conversations by meaning —
search_conversations, thenget_conversationfor a chosen session. - Hand the team a transcript export —
export_chat_logs. - Work the operator inbox —
get_conversation_attentionacross hotels, thenlist_conversation_inboxwithunreadorattentionfor one hotel. - Answer a guest yourself —
reply_to_conversation(a reply takes the conversation over, so the agent stops replying), laterset_conversation_modewithagentto hand back; the agent then answers what the guest asked meanwhile. - Steer the agent without the guest seeing it —
whisper_to_agent; stop it withstop_conversation_turn(kind: whisper, the returnedwhisperId). - Who is this guest —
get_conversation_guest, thenlist_guest_conversationswith itsguestRef. Both needguest-identityaccess on the hotel besides conversation access; without it they are not offered andguestNameis null onlist_recent_conversations.
Before you start
- Send
x-api-key: <key>on every call; the key only reaches/api/v1. GET /api/v1/tools(or MCPtools/list) returns the tools THIS key may run — if a tool below is missing there, you lack a grant; do not retry it.- Client-scoped tools take
clientId(a hotel id).whoamilists the ids you can act on.
Tools
| Tool | What it does | REST | Needs |
|---|---|---|---|
export_chat_logs | Export a hotel's conversation history as a base64-encoded XLSX workbook. | GET /api/v1/client/{clientId}/conversations/export | chat-logs READ (client); plan: chat-logs; read-only |
get_common_questions | What 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/questions | chat-logs READ (client); plan: chat-logs; read-only |
get_conversation | Retrieve 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_attention | How 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/attention | chat-logs READ (any); read-only |
get_conversation_guest | The 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}/guest | chat-logs READ (client), guest-identity READ (client); plan: guest-identity; read-only |
list_conversation_inbox | One 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/inbox | chat-logs READ (client); plan: chat-logs; read-only |
list_conversations | Return raw chat session rows for a client within a date window. | GET /api/v1/client/{clientId}/conversations | chat-logs READ (client); plan: chat-logs; read-only |
list_guest_conversations | Every 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}/conversations | chat-logs READ (client), guest-identity READ (client); plan: guest-identity; read-only |
list_recent_conversations | The 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/recent | chat-logs READ (any); read-only |
mark_conversation_read | Mark 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}/read | chat-logs WRITE (client); plan: chat-logs |
reply_to_conversation | Send 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}/reply | chat-logs EXECUTE (client); plan: chat-logs; composite of set_conversation_mode |
search_conversations | Find a hotel's conversations by the meaning of guest-visible messages. | GET /api/v1/client/{clientId}/conversations/search | chat-logs READ (client); plan: chat-logs; read-only |
send_message | Send 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}/message | update-client READ (client) |
set_conversation_mode | Switch 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}/mode | chat-logs WRITE (client); plan: chat-logs |
stop_conversation_turn | Stop 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}/stop | chat-logs WRITE (client); plan: chat-logs |
whisper_to_agent | Send 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}/whisper | chat-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
get_common_questionsfor the hotel (default last 30 days; raiselimit, orsearchfor a topic such as "parking") — each group has the most common phrasing, how often it was asked and in how many conversations.list_knowledge_gapswithstatus: "OPEN"— the questions the concierge could NOT answer, with occurrence counts. These are the highest-value FAQ entries.- For each FAQ item draft the answer; check the hotel's current wording with
get_conversationon asampleSessionIdsentry orlist_qa_pairswithsearch. - Publish the answers to the concierge with
add_qa_pairs(knowledge skill) so the website FAQ and the chat stay consistent;answer_knowledge_gapwith ananswercloses a gap and creates the live Q&A pair in one call.
Test an answer end to end
send_messagewithclientIdandmessage; keep the returnedsessionId.- Send follow-ups with the same
sessionIdto test multi-turn behaviour. - If the answer is wrong, fix it in the
maison-knowledgeskill and re-send in a NEW session (answers are cached per session).
Take over a conversation and hand it back
get_conversation_attention(optionallyclientIds) — how many conversations need an operator, per hotel.list_conversation_inboxfor the hotel withattention: trueorunread: true;get_conversationto read one.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.- Keep replying with
reply_to_conversation;mark_conversation_readclears unread and attention without replying. set_conversation_modewithmode: "agent"hands the conversation back to the agent, which answers any guest messages left waiting.
Tips
send_messageruns as the operator (client audience), so it may surface tools and data a guest would not see.list_conversationsdefaults to the last 7 days; narrow withfrom/toand raiselimit(max 500). For operator work uselist_conversation_inbox, which adds who holds each conversation, unread and attention.search_conversationsreturns 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_logsreturns the file inline as base64 and refuses exports over 8 MiB — narrow the date window.whisper_to_agentanswers 409verified_sessionon a signed-in guest's web chat and 409no_routeon email conversations; take over andreply_to_conversationinstead.whisper_to_agentneeds the agent to be answering: 409operator_modeonce the conversation is taken over (hand back first, or reply yourself), and 409agent_unavailablewhen the agent could not answer on WhatsApp, Instagram or Messenger (nothing reached the guest).set_conversation_modeis idempotent: asking for the current mode returnschanged: falseand does nothing. A takeover another operator won or already holds is 409mode_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.
# REST
curl -X GET "https://maison-labs.com/api/v1/client/<clientId>/conversations/export" -H "x-api-key: $MAISON_API_KEY"// MCP (https://maison-labs.com/mcp, Streamable HTTP): tools/call
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "export_chat_logs", "arguments": {} } }// 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.