Skip to main content

Chat Handoff to Human Agents

Overview

When the bot cannot answer, or the user types something like "talk to an agent", the system has to switch from bot-driven replies to human-driven ones. The conversation is forwarded to Mbox — a Chatwoot-style live chat platform — and auto-response must be prevented from interrupting while an agent is engaged.

The "currently talking to an agent" state lives in Redis under agent_mode:<lineOaId>:<userId>, paired with the agent_sessions sorted set that acts as the expiry clock for every open session.

Business Flow

Handoff mode — entering agent mode

  1. Receive an MboxHandoffPayload carrying an mboxConfig block: base URL, API token, account ID, inbox ID, LINE webhook URL, timeout and warning durations, the greeting / warning / end / timeout message templates, and the list of exit keywords.
  2. Deduplicate — if agent_mode:<lineOaId>:<userId> already exists, the user is already in agent mode and the job is skipped.
  3. Forward the webhook into Mbox so a conversation is created on that side.
    • The stored webhook at mbox_pending_webhook:<lineOaId>:<userId> is preferred, because a postback event cannot create a conversation in Mbox while the original message that triggered talk_to_agent can.
    • If nothing is stored, the current webhook is used instead. A failed forward is not fatal — it is logged and processing continues. The HTTP timeout is 5 seconds.
  4. Write the Redis agent_mode hash with the full config, warningSent set to 0, and the start timestamp.
  5. Add the member to the agent_sessions sorted set with the score set to the epoch time at which the warning should be sent.
  6. Push the greeting message to the user through the LINE API.

Department picker mode

The service sends a flex message listing the available departments and stores the current webhook under mbox_pending_webhook, so it can be replayed during the real handoff once the user picks a department.

Exit mode

When the user types one of the configured exit keywords, the service resolves the conversation in Mbox, deletes the agent_mode key, removes the member from agent_sessions, and sends the closing message.

Timeout cron (profile cron-scheduler, every minute)

MboxTimeoutService.Run pulls every member of agent_sessions whose score has come due and handles it in two stages.

  • Stage 1 (warningSent is 0) — send the "still waiting for an agent" warning, set warningSent to 1, and push the score forward by (timeoutMinutes - warningMinutes) * 60 seconds.
  • Stage 2 (warningSent is 1) — the session has genuinely timed out: resolve the Mbox conversation, delete the agent_mode key, remove the member from the sorted set, and send the timeout message.
  • Inconsistent state or a missing hash simply gets swept out of the sorted set.

Key Files & Functions

FileResponsibility
internal/mbox/service_handoff.goMboxHandoffService.HandleHandoff, HandleDepartmentPicker, HandleExit, ResolveMboxConversation, forwardWebhook, sendFlexMessage, sendLineMessage, channelAccessToken, plus the MboxConfig and MboxHandoffPayload types and the 5-second forwardTimeout constant
internal/mbox/consumer.goConsumer.HandleMboxHandoff — dispatches on the payload type between exit, department_picker and the default handoff mode
internal/cronscheduler/mbox_timeout.goMboxTimeoutService.Run, processExpiredMember, sendLineMessage
internal/mboxx/mboxx.goMbox REST client, authenticating with the api_access_token header
cmd/worker/main.gorunCronScheduler — wires the consumer and the cron jobs together

Queue: mbox_handoff on the cron-scheduler profile.

Connections to Other Services

  • line-management-webhook-go — matches keywords against the cached webhook_config and publishes the job.
  • Action Execution — the talk_to_agent action is the other producer for this queue.
  • Redis (central to the design) — agent_mode:<lineOaId>:<userId> holds the session hash, agent_sessions is the expiry sorted set, plus mbox_pending_webhook:<lineOaId>:<userId>, mbox_inbox:<inboxId> and webhook_config:<webhookId>.
  • Table line_oa — supplies channel_access_token and message_handling_config.mbox.
  • Mbox REST API — creates and resolves conversations and assigns teams, with a 5-second timeout.
  • LINE APIPOST /v2/bot/message/push for the greeting, warning, end and timeout messages as well as the department flex message.
  • Works together with Live Chat Callback Handling, which receives events coming back from Mbox.