Skip to content

Function Execution

Step 6 of 7

Overview

After defining the functions, it's essential to implement how these functions are executed in AL. This guide will walk you through creating the code that processes the AI's response and calls the appropriate functions.

Processing AI Responses

In the EventAssistToolsImpl.Codeunit.al, you'll define how to handle responses from Azure OpenAI. Here's how to implement the response processing functionality:

1. Open File

Navigate to the file \src\5-EventAssistantCopilot\Implementation\EventAssistToolsImpl.Codeunit.al.

This file will contain the logic to process responses from Azure OpenAI and call the appropriate functions based on the AI's analysis.

2. Add Response Processor

Implement the ProcessResponse procedure to parse the response from Azure OpenAI and execute the relevant function:

procedure ProcessResponse(ResponseText: Text): Text
var
    Response: JsonObject;
    Array: JsonArray;
    Token: JsonToken;
    Object: JsonObject;
begin
    // Parse the JSON response
    if not Response.ReadFrom(ResponseText) then
        exit(ResponseText); // Directly return the response if parsing fails

3. AI Response Format

Assume you asked the next question: "When is John is speaking?"

The response from Azure OpenAI will come in the next format:

{
    "content":null,
    "role":"assistant",
    "tool_calls":[
        {
            "function":{
                "arguments":"{\u0022speakerName\u0022:\u0022John\u0022}",
                "name":"GetSpeakerSchedule"
            },
            "id":"call_fXKvsusE35qdWzQ8klTrGD0s",
            "type":"function"
        }
    ]
}

The response contains the following elements:

  • content: The response content. In case, when the AI decides to execute a function, this field will be empty. Otherwise, it will contain the response text.
  • tool_calls: An array of tool calls. Each tool call contains the function to execute and its arguments. Usually, the AI will recommend only one function to call.
  • function: The function to execute.
  • arguments: The arguments for the function.

Examples:

  • User asks: "How many sessions are planned for the conference?"

    {
        "content": null,
        "role": "assistant",
        "tool_calls": [
            {
                "function": {
                    "arguments": "{}",
                    "name": "GetTotalSessions"
                },
                "id": "call_n0cxDKPQY4eKMxn2ME7Ky5p6",
                "type": "function"
            }
        ]
    }    
    

  • User asks: "How many sessions are planned in the track no. 2 ?"

    {
        "content": null,
        "role": "assistant",
        "tool_calls": [
            {
                "function": {
                    "arguments": "{\"trackNumber\":2}",
                    "name": "GetTotalSessionsByTrack"
                },
                "id": "call_fn00Z7eZ2UlIxRttg5Bct27l",
                "type": "function"
            }
        ]
    }    
    

  • User asks: "How many sessions are planned in the track no." (without track number)

    {
        "content": "Sure, please provide me with the track number for which you want to know the number of planned sessions.",
        "role": "assistant"
    }
    
    In this case, the AI will not recommend any function to call, but it will provide a response to the user, asking for the track number.

4. Extract Content

In case the AI doesn't recommend any function to call, you can directly return the response content to the user. Here's how to extract the content:

Response.Get('content', Token);
if not Token.AsValue().IsNull then
    exit(Token.AsValue().AsText());

5. Extract Tool Calls

If the AI recommends a function to call, you need to extract the function name and arguments from the response. Here's how to extract the tool calls:

// Extract the content or tool calls from the response
Response.Get('tool_calls', Token);
Array := Token.AsArray();

if Array.Get(0, Token) then begin
    Object := Token.AsObject();
    Object.Get('function', Token);
    Object := Token.AsObject();
    Object.Get('name', Token);

    // Determine which function to call based on the function name
    case Token.AsValue().AsText() of
        'GetTotalSessions':
            exit(GetTotalSessions());
        'GetTotalSessionsByTrack':
            exit(GetTotalSessionsByTrack(Object));
        // Other cases will be added by you
        else
            exit('Function not supported.');
    end;
end else
    exit('No actionable data found.');

6. Implement Functions

You already have two functions defined. Here’s a brief overview:

  • GetTotalSessions: Returns the total number of sessions for the conference.
  • GetTotalSessionsByTrack: Accepts a track number and returns the number of sessions in that track, along with session details.

Let's implement these functions in the EventAssistToolsImpl.Codeunit.al:

The goal of the GetTotalSessions function is to return the total number of sessions for the conference. You can return just a number or a formatted string with the total number of sessions.

local procedure GetTotalSessions(): Text
var
    Session: Record "GPT Session";
begin
    Session.SetRange("Project Code", ProjectCode);
    exit('The total number of sessions planned for the conference is ' + Format(Session.Count) + '.');
end;

Note

As you immediately show the response to the user, it makes sense to show formatted text with the total number of sessions, so it feels more natural. In the future release, starting from the v 24.2, you can pass the result to the Azure OpenAI and let it format the final response.

The goal of the GetTotalSessionsByTrack function is to return the total number of sessions for a specific track. It requires a track number as a parameter and returns the number of sessions in that track, along with session details.

local procedure GetTotalSessionsByTrack(Object: JsonObject): Text
var
    Token: JsonToken;
    TrackNumber: Integer;
    Session: Record "GPT Session";
    ResponseText: TextBuilder;
begin
    if not Object.Get('arguments', Token) then
        exit('Please provide the track number');

    Object.ReadFrom(Token.AsValue().AsText());

    if not Object.Get('trackNumber', Token) then
        exit('Please provide the track number');

    TrackNumber := Token.AsValue().AsInteger();

    Session.SetRange("Project Code", ProjectCode);
    Session.SetRange("Track No.", TrackNumber);

    ResponseText.AppendLine('The total number of sessions planned in track ' + Format(TrackNumber) + ' is ' + Format(Session.Count) + '.');
    if Session.FindSet() then
        repeat
            ResponseText.AppendLine(' - ' + Session.Name + ' (' + Format(Session.Date) + ' at ' + Format(Session."Start Time") + ')' + ' ');
        until Session.Next() = 0;

    exit(ResponseText.ToText());
end;

7. Implement More Functions

You are tasked with implementing two additional functions:

  • GetSessionDetailsByName: This should return session details for a given session name.
  • GetSpeakerSchedule: This should return the schedule for a specified speaker.

Use the SearchSessionUsingKeyword helper procedure when implementing GetSessionDetailsByName to filter sessions based on the session name.

8. Function Guidelines

When implementing these functions, ensure you:

  • Handle parameters correctly by extracting them from the JSON object passed by the Azure OpenAI.
  • Return meaningful and formatted responses that can be directly used or displayed by the PromptDialog page.

Conclusion

By following these steps, you will enable the Event Assistant Copilot to process user queries intelligently and interact with backend functions effectively, enhancing the user experience within Dynamics 365 Business Central.

This capability unlocks a wide range of possibilities in the "ask your data" area, allowing you to leverage internal functions to provide meaningful and formatted responses to user queries.

Next Steps

Move on to the next step to understand how many skills you can add to the AI Event Assistant, what are the limits, and how to manage them.