#Call forward

1 messages · Page 1 of 1 (latest)

glossy timber
#

Definitely 🙂

wide idol
#

I'd love to have the call forwarding/transfer ability.

#

The idea is to bridge an ongoing call with an AI agent to a human agent.

wide idol
#

BTW, I solved this problem by writing some code on top of the boilerplate from the docs.

#

I setup a client tool calling for the agent on 11labs dashboard with the name "transfer_to_human"

#
                  console.log("[ElevenLabs] Received client tool call:", message.client_tool_call);
                  if (message.client_tool_call?.tool_name === "transfer_to_human") {
                    try {
                      await handleTransfer();
                      // Send success response
                      elevenLabsWs.send(JSON.stringify({
                        type: "client_tool_result",
                        tool_call_id: message.client_tool_call.tool_call_id,
                        result: "Transfer initiated successfully",
                        is_error: false
                      }));
                      // Don't close immediately - let Twilio handle the transfer
                    } catch (error) {
                      console.error("[ElevenLabs] Transfer failed:", error);
                      // Send error response
                      elevenLabsWs.send(JSON.stringify({
                        type: "client_tool_result",
                        tool_call_id: message.client_tool_call.tool_call_id,
                        result: error.message,
                        is_error: true
                      }));
                    }
                  }
                  break;
#

I added this case in the elevenLabsWs.on("message") handler

#

This is how I setup the handleTransfer() function:

        if (!HUMAN_AGENT_PHONE_NUMBER) {
          console.error("[Transfer] Cannot transfer: HUMAN_AGENT_PHONE_NUMBER not configured");
          throw new Error("Transfer not available - no agent number configured");
        }

        if (!callSid) {
          console.error("[Transfer] Cannot transfer: No active call");
          throw new Error("No active call to transfer");
        }

        // First, notify Twilio WebSocket about the transfer
        console.log("[Transfer] Notifying Twilio about transfer");
        ws.send(JSON.stringify({
          event: "transfer",
          streamSid,
          transferTarget: HUMAN_AGENT_PHONE_NUMBER
        }));

        // Then update the call with new TwiML
        const twiml = `<?xml version="1.0" encoding="UTF-8"?>
          <Response>
            <Say>Please hold while I transfer you to a human agent.</Say>
            <Dial>${HUMAN_AGENT_PHONE_NUMBER}</Dial>
          </Response>`;
        
        console.log(`[Transfer] Transferring call ${callSid} to ${HUMAN_AGENT_PHONE_NUMBER}`);
        await twilioClient.calls(callSid)
          .update({
            twiml: twiml
          });
        
        console.log("[Transfer] Transfer successful");
      }
#

To handle the call transfer from Twilio:

            case "transfer":
              console.log("[Twilio] Received transfer event:", msg);
              if (HUMAN_AGENT_PHONE_NUMBER) {
                if (msg.transferTarget === HUMAN_AGENT_PHONE_NUMBER) {
                  console.log(`[Twilio] Transferring call ${callSid} to human agent at ${HUMAN_AGENT_PHONE_NUMBER}`);
                  try {
                    const twiml = `<?xml version="1.0" encoding="UTF-8"?>
                      <Response>
                        <Say>Please hold while I transfer you to a human agent.</Say>
                        <Dial>${HUMAN_AGENT_PHONE_NUMBER}</Dial>
                      </Response>`;
                    await twilioClient.calls(callSid)
                      .update({
                        twiml: twiml
                      });
                    // Send transfer-complete event
                    ws.send(JSON.stringify({
                      event: "transfer-complete",
                      streamSid
                    }));
                  } catch (error) {
                    console.error("[Twilio] Error transferring call:", {
                      message: error.message,
                      code: error.code,
                      status: error.status,
                      moreInfo: error.moreInfo
                    });
                  }
                } else {
                  console.error("[Twilio] Transfer target mismatch:", {
                    expected: HUMAN_AGENT_PHONE_NUMBER,
                    received: msg.transferTarget
                  });
                }
              } else {
                console.error("[Twilio] Cannot transfer: HUMAN_AGENT_PHONE_NUMBER not configured");
              }
              break;
#

And when the transfer is completed, I'm closing the connection to ElevenLabs.

              console.log("[Twilio] Transfer completed, closing ElevenLabs connection");
              if (elevenLabsWs?.readyState === WebSocket.OPEN) {
                elevenLabsWs.close();
              }
              break;
#

I think the next checkpoint would be how to transfer context/data from the call to the human agent before they take over.

coral moth
#

Hey, did you ever get this working?