Esta página aún no está traducida al español — mostrando la versión en inglés.

Human handoff

Transfer a conversation to a human agent. Configurable conditions, business-hours schedule, offline message, and contact capture.

The Human Handoff tool (key: "handoff", module Chatbotgen.AI.Tools.Handoff) gives the chatbot a way to stop answering and put a real person in the loop.

Tool description (verbatim from seed)

Human Handoff — Transfer conversations to human agents when the AI can't help. Configure when and why handoffs happen.

Function definition (what the LLM sees)

Verified from handoff.ex:

  • Name: request_human_handoff
  • Description: "Transfer the conversation to a human agent when you cannot help or the user requests one."
  • Parameters:
    • reason (string, required) — "Brief reason why human handoff is needed"

Configuration fields

Enabling the tool shows an inline form with 11 fields. Every field has a default from the seed, so saving without edits already gives you a working configuration.

Handoff Conditions (textarea)

  • Label: "Handoff Conditions"
  • Not required
  • Default (verbatim):

Transfer the conversation to a human agent when:

  • The user explicitly asks to speak with a human
  • You cannot answer their question after trying
  • The topic involves complaints, refunds, billing issues, or sensitive matters
  • The user seems frustrated or dissatisfied with your answers

Do NOT transfer for simple questions you can answer from the knowledge base.

This is stored on config["prompt"] and injected into the system prompt for the conversation.

Offline Message (textarea)

  • Label: "Offline Message"
  • Not required
  • Default: "Our team is currently offline. Please leave your message and we'll get back to you as soon as possible."

Stored on config["offline_message"]. Returned as the chatbot's reply when the tool fires outside business hours (see below).

Enable Schedule (checkbox)

  • Label: "Enable Schedule"
  • Default: "false" (stored as string because the UI serializes checkboxes as "true" / "false")

When disabled, the tool ignores business hours entirely — every call completes the handoff.

Available Days (text)

  • Label: "Available Days (comma-separated, e.g. mon,tue,wed,thu,fri)"
  • Default: mon,tue,wed,thu,fri

Compared at runtime against the current weekday using three-letter lowercase names (mon, tue, wed, thu, fri, sat, sun). The mapping comes from handoff.ex's day_name/1.

Start Time (text)

  • Label: "Start Time (HH:MM, 24h)"
  • Default: 09:00

End Time (text)

  • Label: "End Time (HH:MM, 24h)"
  • Default: 18:00

The within-schedule check is day in days and time >= start_time and time < end_time — end time is exclusive.

Timezone (text)

  • Label: "Timezone (e.g. America/Bogota)"
  • Default: America/Bogota

Use a standard IANA timezone identifier. If DateTime.now(tz) returns {:error, _} (unknown tz), the tool assumes agents are available.

Enabled Channels (text)

  • Label: "Enabled Channels (comma-separated — widget,whatsapp,telegram). Leave empty for all."
  • Default: widget,whatsapp,telegram

The channels credential is used by AI.ToolRunner to filter tools per conversation channel. Clearing this field enables the tool on all channels.

Collect visitor name/email before handoff (checkbox)

  • Label: "Collect visitor name/email before handoff"
  • Default: "true"

Stored on config["collect_contact"]. Any value other than the string "false" is treated as true.

Contact capture mode (text)

  • Label: "Contact capture mode (required | optional)"
  • Default: required

Passed through to the rich response as contact_mode.

Fields to collect (text)

  • Label: "Fields to collect (comma-separated — name,email,phone)"
  • Default: name,email

Split on ,, trimmed, empty strings removed. Passed through to the rich response as contact_fields.

Runtime flow (verified from handoff.ex's call/2)

When the LLM calls request_human_handoff:

  1. The reason arg is pulled out (falls back to "User requested human assistance" if missing).
  2. If schedule is enabled AND the current time is outside the schedule window, the tool returns ONLY the offline message as the chat reply — no structured handoff signal is emitted. The conversation stays in its current status.
  3. Otherwise, the tool returns:
    • Text reply: "I'm connecting you with a human agent. Someone from our team will be with you shortly."
    • Rich response:
      type: "handoff"
      reason: 
      collect_contact: config["collect_contact"] != "false"
      contact_mode: config["contact_mode"] || "required"
      contact_fields: 

System prompt injection (verified from handoff.ex's system_context/1)

On every conversation, the tool adds the following to the system prompt:

You have a tool called "request_human_handoff" to transfer conversations to a human agent.
{Handoff Conditions}
{schedule note, if any}

The schedule note is:

  • "Human agents are currently AVAILABLE." when the schedule is enabled and we're within hours
  • "Human agents are currently OFFLINE. If the user requests a human, inform them agents are unavailable and offer to take a message." when the schedule is enabled and we're outside hours
  • empty string when the schedule is disabled

Plan notes

Enabling tools at all requires the AI Tools feature. The Tools page's feature-lock card points to Growth — $79/mo. See Plans & pricing for the feature matrix.