Dialogue Cloud

How to configure Last Agent Routing in Dialogue Studio

This article is an example of a Last Agent Routing flow built in AnywhereNow Dialogue Studio. This scenario describes the setup of a flow which will see if the current caller has spoken to an agent before in a past (limited) period. It will also describe the mechanism and maintenance tips behind is as well as the known limitations.

Preview

Configure

  1. Login to your Dialogue Studio environment

  2. Open or Create a Tab where you want to add the Last Agent Routing

  3. From the menu in the top right, select Import and add the following JSON.

    Copy
    JSON
    [{"id":"9d1897bf.e51ac8","type":"tab","label":"Last Agent Routing","disabled":false,"info":""},{"id":"8feaa27b.8ff3e","type":"group","z":"9d1897bf.e51ac8","name":"Create Last Agent Memory","style":{"label":true},"nodes":["d8803b35.378348","59308899.4ad098","60157bc3.eafbc4","5436bcda.d26f54","4c4c9009.9fb2e","b22fd6d.27fee28","f4d3210d.480b2","20215017.b623","141f13d8.3ad64c"],"x":234,"y":39,"w":912,"h":262},{"id":"cde2b9be.532788","type":"group","z":"9d1897bf.e51ac8","name":"Route based on Last Agent","style":{"label":true},"nodes":["136cd64f.8aa9ca","39e684fe.3fb4fc","c72e2fdb.81a21","b94ee88f.532b08","f177a31e.3d3f","796f8a7c.8a19c4","df9946a4.6bbd18","dca895d1.50ef78","aa4e1cc6.49af3"],"x":234,"y":339,"w":1392,"h":222},{"id":"d3bbfa2b.946f88","type":"group","z":"9d1897bf.e51ac8","name":"Cleanup Memory","style":{"label":true},"nodes":["d35e88d9.761b88","3a77a675.eb31da"],"x":1214,"y":139,"w":432,"h":82},{"id":"d8803b35.378348","type":"any-red-event-bus","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"","config":"","filtertype":"DialogueParticipantAddedEvent,DialogueQueueEnteredEvent,DialogueEndedEvent","x":320,"y":200,"wires":[["20215017.b623"]]},{"id":"59308899.4ad098","type":"switch","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"","property":"payload.event.roles[0]","propertyType":"msg","rules":[{"t":"eq","v":"Customer","vt":"str"},{"t":"eq","v":"Agent","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":140,"wires":[["60157bc3.eafbc4"],["5436bcda.d26f54"]]},{"id":"60157bc3.eafbc4","type":"function","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"Create Last Agent Record for customer","func":"const { sipUri, dialogueId, timestamp } = msg.payload.event;\nconst phone = sipUri.slice(4).split(\"@\")[0];\n\nflow.set(`${dialogueId}`, {phone});\n\nconst newCustomer = flow.get(`${phone}`) || 0;\n\nif (newCustomer === 0 ){\nflow.set(`${phone}`, {dialogueId, timestamp });\n}\n\nconst lastAgent = flow.get(`${phone}`).agentUri || 0;\n\nif (lastAgent === 0 ){\nflow.set(`${phone}`, {dialogueId, timestamp });\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":80,"wires":[[]]},{"id":"5436bcda.d26f54","type":"function","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"Store previous agent in Last Agent Record","func":"const { sipUri, displayName, dialogueId, timestamp } = msg.payload.event;\n\nconst match_customer = flow.get(`${dialogueId}`).phone;\n\nconst customer = flow.get(`${match_customer}`);\nconst queueName = customer.queueName\n\nflow.set(`${match_customer}`, {dialogueId, timestamp, agentUri: sipUri, queueName, agentDisplayName: displayName });\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":960,"y":140,"wires":[[]]},{"id":"136cd64f.8aa9ca","type":"any-red-incoming-call","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"","config":"","filtertype":"audiovideo","x":400,"y":480,"wires":[["c72e2fdb.81a21"]]},{"id":"39e684fe.3fb4fc","type":"any-red-say","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"","text":"Welcome","dataType":"str","saymethod":"Default","voice":"","x":1220,"y":440,"wires":[["796f8a7c.8a19c4"]]},{"id":"c72e2fdb.81a21","type":"function","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"Retreive Last Agent","func":"const phone = msg.session.sipUri.slice(4).split(\"@\")[0];\nconst lar = flow.get(`${phone}`);\nmsg.lastAgent = lar\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":480,"wires":[["b94ee88f.532b08"]]},{"id":"b94ee88f.532b08","type":"switch","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"Check if a last agent is known","property":"lastAgent.agentUri","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":970,"y":480,"wires":[["39e684fe.3fb4fc"],["f177a31e.3d3f"]]},{"id":"f177a31e.3d3f","type":"any-red-say","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"","text":"\"Welcome back, we will connect you with \" & lastAgent.agentDisplayName","dataType":"jsonata","saymethod":"Default","voice":"","x":1270,"y":520,"wires":[["df9946a4.6bbd18"]]},{"id":"4c4c9009.9fb2e","type":"function","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"Store previous skill in Last Agent Record","func":"const {queueName, dialogueId, timestamp } = msg.payload.event;\n\nconst phone = flow.get(`${dialogueId}`).phone;\n\nconst lastAgent = flow.get(`${phone}`).agentUri || 0;\n\nif (lastAgent === 0 ){\nflow.set(`${phone}`, {dialogueId, timestamp, queueName});\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":960,"y":200,"wires":[[]]},{"id":"b22fd6d.27fee28","type":"switch","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"","property":"payload.event.queueId","propertyType":"msg","rules":[{"t":"eq","v":"-1","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":200,"wires":[[],["4c4c9009.9fb2e"]]},{"id":"796f8a7c.8a19c4","type":"any-red-action","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"","sweetName":"Empty action","actionType":"enqueue","fromSessionId":"session.id","fromDataType":"msg","toSessionId":"fromSessionId","toDataType":"msg","skill":"Support","skillDataType":"str","sip":"","sipDataType":"str","agentSips":"","agentSipsDataType":"str","config":"4f3ba918.075e48","questionsfilter":"","questionid":"","x":1510,"y":440,"wires":[]},{"id":"f4d3210d.480b2","type":"function","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"Cleanup disconnected sessions","func":"const dialogueId = msg.payload.event.dialogueId\n\nflow.set(`${dialogueId}`)\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":260,"wires":[[]]},{"id":"df9946a4.6bbd18","type":"any-red-action","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"","sweetName":"Empty action","actionType":"preferredhunt","fromSessionId":"session.id","fromDataType":"msg","toSessionId":"fromSessionId","toDataType":"msg","skill":"lastAgent.queueName","skillDataType":"msg","sip":"","sipDataType":"str","agentSips":"lastAgent.agentUri","agentSipsDataType":"msg","config":"4f3ba918.075e48","questionsfilter":"","questionid":"","x":1520,"y":520,"wires":[]},{"id":"20215017.b623","type":"switch","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"","property":"payload.eventType","propertyType":"msg","rules":[{"t":"eq","v":"DialogueParticipantAddedEvent","vt":"str"},{"t":"eq","v":"DialogueQueueEnteredEvent","vt":"str"},{"t":"eq","v":"DialogueEndedEvent","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":490,"y":200,"wires":[["59308899.4ad098"],["b22fd6d.27fee28"],["f4d3210d.480b2"]]},{"id":"141f13d8.3ad64c","type":"comment","z":"9d1897bf.e51ac8","g":"8feaa27b.8ff3e","name":"ToDo: Add UCC","info":"","x":340,"y":140,"wires":[]},{"id":"dca895d1.50ef78","type":"comment","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"Change to preferred Skill","info":"","x":1490,"y":380,"wires":[]},{"id":"aa4e1cc6.49af3","type":"comment","z":"9d1897bf.e51ac8","g":"cde2b9be.532788","name":"ToDo: Add UCC","info":"","x":340,"y":440,"wires":[]},{"id":"d35e88d9.761b88","type":"function","z":"9d1897bf.e51ac8","g":"d3bbfa2b.946f88","name":"Cleanup Memory","func":"msg.clear = flow.keys()\n\nfor (let i = 0; i< msg.clear.length;i++) {\nflow.set(msg.clear[i])\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1530,"y":180,"wires":[[]]},{"id":"3a77a675.eb31da","type":"inject","z":"9d1897bf.e51ac8","g":"d3bbfa2b.946f88","name":"","props":[],"repeat":"","crontab":"00 12 * * 0","once":false,"onceDelay":0.1,"topic":"","x":1310,"y":180,"wires":[["d35e88d9.761b88"]]}]
  4. Open the EventBus and Select or Configure a server. For more information, see: Create your first flow

  5. Open the Incoming Call and Select or Configure a server. For more information, see: Create your first flow

  6. Open the Enqueue and enter a Skill

  7. To test your Last Agent Routing, initiate a phone call with the UCC A Unified Contact Center, or UCC, is a queue of interactions (voice, email, IM, etc.) that are handled by Agents. Each UCC has its own settings, IVR menus and Agents. Agents can belong to one or several UCCs and can have multiple skills (competencies). A UCC can be visualized as a contact center “micro service”. Customers can utilize one UCC (e.g. a global helpdesk), a few UCC’s (e.g. for each department or regional office) or hundreds of UCC’s (e.g. for each bed at a hospital). They are interconnected and can all be managed from one central location. and have an Agent accept the conversation. Now call again to see if the Last Agent Routing has been updated.

  8. If you need to customize or extend the IVR Interactive Voice Response, or IVR, is a telephone application to take orders via telephone keypad or voice through a computer. By choosing menu options the caller receives information, without the intervention of a human operator, or will be forwarded to the appropriate Agent., you can open the Tab, modify the nodes and responses as needed, and save your changes.

  9. Test the IVR again to make sure it works.

  10. Congratulations, you have now successfully configured Last Agent Routing in Dialogue Studio!

Explanation

This Dialogue Studio flow will trigger at an incoming conversation with a customer. It will route incoming calls to the last agent that the customer spoke to in the past, if available. If the agent isn't available, it will fallback to the previous skill. If the customer has never spoken to an agent it will route to a standard Skill.

Setup EventBus

The flow listens for events related to UCC dialogues, such as DialogueParticipantAddedEvent, DialogueQueueEnteredEvent, and DialogueEndedEvent, using the EventBus node.

Storing the Last Agent Routing in memory

When a customer dials in, the flow creates a memory record of the customer's phone number and sets the record's dialogue ID and timestamp. This is done using a switch node and a function node. The memory record is stored in the flow context using the flow.set() method. If the customer has called before, the flow retrieves the existing record from memory using flow.get().

When an agent joins the call, the flow stores the agent's SIP The Session Initiation Protocol, or SIP, is a protocol for multimedia communication (audio, video and data communication). SIP is also used for Voice over IP (VoIP). SIP has interactions with other Internet protocols such as HTTP and SMTP. URI and display name, as well as the queue name, in the memory record. The function node that handles this logic retrieves the customer's phone number from the previous memory record and updates the memory record with the new agent information.

Setup the retention policy

To ensure that the memory does not become full, it is necessary to set up a retention policy for the flow that has been created in memory. This can be achieved by scheduling an inject that runs every week on Sunday to automatically clean up the memory. This will help to optimize the performance of the system and prevent it from becoming overloaded with unnecessary data.

Setup Incoming conversation

The flow listens for incoming calls using the Incoming conversation node. When a call comes in, the flow retrieves the customer's phone number from the memory record using the flow.get() method.

Setup Last Agent Routing logic

The flow retrieves the customer's last agent information from the memory record, if available, using the flow.get() method. If the last agent information is available, the flow forwards the call to the corresponding agent using a PreferredHunt node. If the last agent information is not available, the flow forwards the call to the first available agent in the queue using the Enqueue node.

In both scenario's the flow also includes a Say node that plays a welcome message to the caller before routing the call to an agent.

Limitations

It is essential to note that when restarting the Dialogue Studio instance, the memory is purged, which also occurs during a Bundle update or on request. As a result, all records stored in memory will be lost and require re-creation. This limitation may not be problematic if Last Agent Routing rules are used for a short duration.

To avoid losing critical routing rules, it is recommended to store the recording in persistent storage, such as a SQL database. This will enable you to retrieve data even if the Dialogue Studio instance is restarted. Alternatively, you can create a daily backup of the data and restore it to memory after restarting Dialogue Studio.

It's crucial to keep in mind that memory storage has its limitations, particularly when it comes to critical or persistent routing rules. By storing data in a more permanent form, you can guarantee its availability when required.