myContactCenterManual

Agent script examples

Complete C# examples for customer records, time-dependent logout and activity, qualification queries and status lights in V10.

Each code block is a standalone agent script. The system has only one such script: combine the required events in a single AgentScript class instead of copying several classes together. Each event can be overridden only once. These examples use the public V10 interface, not old VB scripts.

For setup, see Agent script; for data, see Product data. Adapt the CRM address, times and IDs. Test actions with test agents first.

Template and events

The Agent API has not yet been assigned in the constructor; use it only in events. This template reacts to a state change of one of your own conversations. The state parameter represents that change; conversation.State may already contain a newer state when it is processed.

using System;
using ilogixx.SharedFiles.GeneralDefinitions;
using ilogixx.SharedFiles.GeneralEnums;

namespace ilogixx.Agent;

public sealed class AgentScript : MyCCAgentScript
{
    public override void My_ConversationStateChanged(Struct_Conversation conversation, ConversationState previousState, ConversationState state)
    {
        try
        {
            if (conversation is null) return;

            Trace.Info("Conversation state changed", state);
        }
        catch (Exception ex)
        {
            Trace.Error(ex);
        }
    }
}

Commands and responses

Command Effect and limitations
BrowseTo(url, true) opens an address in a new tab in the Browser module
Logoff() requests logout; the response and, where applicable, a dialog determine what happens next
Activity(true) requests the start of an activity; the activity is selected in the provided dialog
Activity(false) ends the current activity
Wrapup(true) requests normal wrap-up
Agent.GetLanguageQualification(languageId) reads an effective language qualification as a number
Agent.GetSkillQualification(skillId, qualificationType) reads an effective skill qualification for the selected conversation type
ShowBusyLight(state) sets a connected, supported status light based on a state

A request does not confirm that an action has been performed. Restrictions, permissions and user decisions still apply. My_AgentLogoffPermissionReceived and My_AgentActivityPermissionReceived provide the respective response. Do not request the same action again from these events, as this could create a loop. For more signatures, see Events and commands.

Open the customer record once per conversation

A flow has attached “Kundennummer” (customer number) as a data item. This example opens the customer record when an incoming call first connects. It tracks all conversations for which a record has been opened, so that holding and retrieving a call does not create a second tab even when handling parallel conversations. When a conversation is removed, its ID is removed from local memory.

using System;
using System.Collections.Generic;
using ilogixx.SharedFiles.GeneralDefinitions;
using ilogixx.SharedFiles.GeneralEnums;

namespace ilogixx.Agent;

public sealed class AgentScript : MyCCAgentScript
{
    private readonly HashSet<string> openedConversations = [];
    private const string customerNumberKey = "Kundennummer";
    private const string customerPage = "https://crm.example.com/kunde";

    public override void My_ConversationStateChanged(Struct_Conversation conversation, ConversationState previousState, ConversationState state)
    {
        try
        {
            if (conversation is null || state != ConversationState.Connected || !conversation.IsInboundCall) return;
            if (openedConversations.Contains(conversation.Id)) return;

            string customerNumber = conversation.AttachedData?.StringValue(customerNumberKey);
            if (string.IsNullOrEmpty(customerNumber)) return;

            string url = $"{customerPage}?nr={Uri.EscapeDataString(customerNumber)}";
            BrowseTo(url, true);
            openedConversations.Add(conversation.Id);
        }
        catch (Exception ex)
        {
            Trace.Error(ex);
        }
    }

    public override void My_ConversationUnregistered(Struct_Conversation conversation)
    {
        if (conversation is null) return;

        openedConversations.Remove(conversation.Id);
    }
}

If the customer number is missing when the call connects, no page opens. The example does not query the CRM or replace its login. The stored IDs apply only to this script instance and are lost when the script is replaced or the program restarts.

Request logout after a specified time

From 18:00 local workstation time, this example requests logout as soon as no conversations are being handled. It does not end any conversation. It checks on login, changes to the idle state, and removal of one of your own conversations. Without one of these events, there is no request precisely at 18:00. This also applies after replacing a script: the first check occurs only on the next relevant event.

using System;
using ilogixx.SharedFiles.GeneralDefinitions;

namespace ilogixx.Agent;

public sealed class AgentScript : MyCCAgentScript
{
    private DateTime lastRequestDate = DateTime.MinValue;
    private static readonly TimeSpan logoffTime = new(18, 0, 0);

    private void CheckLogoff()
    {
        try
        {
            DateTime now = DateTime.Now;
            if (Agent is null || !Agent.IsLogin || now.TimeOfDay < logoffTime) return;
            if (lastRequestDate == now.Date || Agent.TotalNumberOfConversations != 0) return;

            lastRequestDate = now.Date;
            Logoff();
        }
        catch (Exception ex)
        {
            Trace.Error(ex);
        }
    }

    public override void My_AgentLogon()
    {
        CheckLogoff();
    }

    public override void My_AgentIdleChanged(bool state)
    {
        CheckLogoff();
    }

    public override void My_ConversationUnregistered(Struct_Conversation conversation)
    {
        CheckLogoff();
    }
}

At most one request is made per calendar day per script instance. A denied or canceled request is not automatically repeated. The daily marker resets when the script is replaced or the program restarts. This example is not an exact timer or a persistently stored work schedule.

Request an activity after a specified time for a skill

From 12:00, an activity is requested if the agent is qualified for incoming calls in the skill with ID 42, is not handling any conversations and is not already pausing. Change the ID. Checks run on the same events as in the logout example, not on a timer.

Activity(true) does not automatically select a particular activity. The permission check and activity selection in Agent remain in place. For automatic states, see also Availability.

using System;
using ilogixx.SharedFiles.GeneralDefinitions;
using ilogixx.SharedFiles.GeneralEnums;

namespace ilogixx.Agent;

public sealed class AgentScript : MyCCAgentScript
{
    private DateTime lastRequestDate = DateTime.MinValue;
    private static readonly TimeSpan activityTime = new(12, 0, 0);
    private const int targetSkillId = 42;

    private void CheckActivity()
    {
        try
        {
            DateTime now = DateTime.Now;
            if (Agent is null || !Agent.IsLogin || now.TimeOfDay < activityTime) return;
            if (lastRequestDate == now.Date || Agent.IsPausing || Agent.TotalNumberOfConversations != 0) return;
            if (!Agent.HasSkillQualification(targetSkillId, SkillQualificationType.InboundCall)) return;

            lastRequestDate = now.Date;
            Activity(true);
        }
        catch (Exception ex)
        {
            Trace.Error(ex);
        }
    }

    public override void My_AgentLogon()
    {
        CheckActivity();
    }

    public override void My_AgentIdleChanged(bool state)
    {
        CheckActivity();
    }

    public override void My_ConversationUnregistered(Struct_Conversation conversation)
    {
        CheckActivity();
    }
}

The same daily marker as in the logout example applies. A qualification only for chat does not trigger the request: the selected type is InboundCall.

Read effective qualifications

On login and configuration changes, the effective levels for a skill and a language are logged. Adapt the IDs. A lower valid number is better; KnowledgeLevel.None means not qualified. Assignments are not changed.

using System;
using ilogixx.SharedFiles.GeneralEnums;

namespace ilogixx.Agent;

public sealed class AgentScript : MyCCAgentScript
{
    private const int targetSkillId = 42;
    private const int targetLanguageId = 7;

    private void ReadQualifications()
    {
        try
        {
            if (Agent is null) return;

            int skillLevel = Agent.GetSkillQualification(targetSkillId, SkillQualificationType.InboundCall);
            int languageLevel = Agent.GetLanguageQualification(targetLanguageId);
            Trace.Info("Effective qualification levels", skillLevel, languageLevel);
        }
        catch (Exception ex)
        {
            Trace.Error(ex);
        }
    }

    public override void My_AgentLogon()
    {
        ReadQualifications();
    }

    public override void My_AgentConfigurationChanged()
    {
        ReadQualifications();
    }
}

For more information, see Qualification data.

Update a status light

When conversations change, the light shows the agent’s effective state, including conversations handled in parallel. Without an effective conversation, the presence state is used. A supported and configured light is required; this does not refer to the color of icons in the user interface.

using System;
using ilogixx.SharedFiles.GeneralDefinitions;
using ilogixx.SharedFiles.GeneralEnums;

namespace ilogixx.Agent;

public sealed class AgentScript : MyCCAgentScript
{
    private void UpdateBusyLight()
    {
        try
        {
            if (Agent is null) return;

            ConversationState state = Agent.EffectiveState;
            if (state == ConversationState.Inactive)
            {
                ShowBusyLight(Agent.RichPresenceState);
            }
            else
            {
                ShowBusyLight(state);
            }
        }
        catch (Exception ex)
        {
            Trace.Error(ex);
        }
    }

    public override void My_ConversationStateChanged(Struct_Conversation conversation, ConversationState previousState, ConversationState state)
    {
        UpdateBusyLight();
    }

    public override void My_AgentPresenceStateChanged(RichPresenceState richPresenceState)
    {
        UpdateBusyLight();
    }
}

Check before use

Check login after the target time, active and parallel conversations, missing attached data, denied actions and script changes. The time examples use events and an in-memory marker. They do not start their own timers or background threads. Holding and retrieving a conversation must not reopen a customer record that has already been opened for that conversation.

    ↑ ↓ select · Enter open · Esc close