Page 4312 Agent Task Log Entry, source in 27
Source272829metadata in 27
src/System Application/App/Agent/Troubleshooting/AgentTaskLogEntry.Page.al465 lines, Copyright (c) Microsoft Corporation. MIT
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace System.Agents.Troubleshooting;
using System.Agents;
using System.Security.AccessControl;
page 4312 "Agent Task Log Entry"
{
PageType = Card;
ApplicationArea = All;
SourceTable = "Agent Task Log Entry";
Caption = 'Agent Task Log Entry (Preview)';
DataCaptionExpression = StrSubstNo(PageCaptionLbl, rec.ID, Rec.Description);
InsertAllowed = false;
ModifyAllowed = false;
DeleteAllowed = false;
AboutTitle = 'About agent task log entry';
AboutText = 'Use this detailed log of what the AI agent found on the page and how it acted autonomously to troubleshoot agent issues. AI-generated content may be incorrect.';
InherentEntitlements = X;
InherentPermissions = X;
layout
{
area(Content)
{
group(General)
{
Caption = 'What the agent decided';
AboutTitle = 'General information';
AboutText = 'General information about the log entry. Click show more to see advanced details about the execution.';
Editable = false;
Visible = IsAgentAction;
field(Description; Rec.Description)
{
Caption = 'Description';
ToolTip = 'Specifies the description of the log entry.';
Importance = Promoted;
trigger OnDrillDown()
begin
if (Rec.Description <> '') then
Message(Rec.Description);
end;
}
field(Reason; Rec.Reason)
{
Caption = 'Reason';
ToolTip = 'Specifies the reason, provided by the agent, for the log entry.';
Importance = Promoted;
trigger OnDrillDown()
begin
if (Rec.Reason <> '') then
Message(Rec.Reason);
end;
}
field(Details; LogEntryDetailsTxt)
{
Caption = 'Details';
ToolTip = 'Specifies the details of the log entry.';
Importance = Promoted;
trigger OnDrillDown()
begin
if (LogEntryDetailsTxt <> '') then
Message(LogEntryDetailsTxt);
end;
}
field(Type; Rec.Type)
{
Caption = 'Type';
ToolTip = 'Specifies the type of the log entry.';
Importance = Additional;
}
field(SystemCreatedAt; Rec.SystemCreatedAt)
{
Caption = 'Timestamp';
ToolTip = 'Specifies the date and time when the log entry was created.';
Importance = Additional;
}
field(UserFullName; Rec."User Full Name")
{
Caption = 'User full name';
Tooltip = 'Specifies the full name of the user that was involved';
Importance = Additional;
}
field(TaskID; Rec."Task ID")
{
Caption = 'Task ID';
ToolTip = 'Specifies the ID of the task that was executed.';
Importance = Additional;
}
field(AgentName; AgentName)
{
Caption = 'Agent name';
ToolTip = 'Specifies the name of the agent that performed the tasks.';
Importance = Additional;
}
field(IsDecision; IsDecisionTxt)
{
Caption = 'Decision Point';
ToolTip = 'Specifies if the agent made a decision at this point, or whether this was executed as part of a previous decision.';
Importance = Additional;
}
field(IsSuccess; IsSuccess)
{
Caption = 'Success';
ToolTip = 'Specifies if the operation was successful.';
Importance = Additional;
}
}
group(GeneralOther)
{
Caption = 'What happened';
AboutTitle = 'General information';
AboutText = 'General information about the log entry. Click show more to see advanced details about the execution.';
Editable = false;
Visible = not IsAgentAction;
field(DescriptionOther; Rec.Description)
{
Caption = 'Description';
Importance = Promoted;
}
field(DetailsOther; LogEntryDetailsTxt)
{
Caption = 'Details';
ToolTip = 'Specifies the details of the log entry.';
Importance = Promoted;
trigger OnDrillDown()
begin
Message(LogEntryDetailsTxt);
end;
}
field(TypeOther; Rec.Type)
{
Caption = 'Type';
Importance = Additional;
}
field(TimestampOther; Rec.SystemCreatedAt)
{
Caption = 'Timestamp';
ToolTip = 'Specifies the date and time when the log entry was created.';
Importance = Additional;
}
field(NameOther; Rec."User Full Name")
{
Caption = 'User full name';
Tooltip = 'Specifies the full name of the user that took the decision.';
Importance = Promoted;
}
}
part(InputMessagePart; "Agent Task Message ListPart")
{
Caption = 'What the agent received';
SubPageLink = "Task ID" = field("Task ID");
AboutTitle = 'What the agent received';
AboutText = 'Shows the message the agent received as part of this task.';
Enabled = false;
Visible = Rec.Type = Rec.Type::"Input Message";
}
part(OutputMessagePart; "Agent Task Message ListPart")
{
Caption = 'What the agent wrote';
SubPageLink = "Task ID" = field("Task ID");
AboutTitle = 'What the agent wrote';
AboutText = 'Shows the message the agent wrote as part of this task.';
Enabled = false;
Visible = (Rec.Type = Rec.Type::"Output Message Draft") or (Rec.Type = Rec.Type::"Output Message");
}
part(LogsPart; "Agent Task Log Entry ListPart")
{
Caption = 'What other actions were decided at the same time';
Visible = IsLogPageVisible;
SubPageLink = "Task ID" = field("Task ID");
AboutTitle = 'What other actions were decided at the same time';
AboutText = 'The agent can take multiple actions from the same decision. This lists the log entries related to the actions taken by the agent for this particular entry.';
}
group(PageContentGroup)
{
Caption = 'What the agent saw';
Visible = IsSerializedPageVisible;
AboutTitle = 'What the agent saw';
AboutText = 'The view of the page the agent saw before taking a decision. The data format is subject to change, therefore do not reference it too specifically in instructions.';
field(PageContent; SerializedPageJson)
{
Caption = 'Page content';
ExtendedDatatype = RichContent;
MultiLine = true;
ShowCaption = false;
Editable = false;
trigger OnDrillDown()
begin
Message(SerializedPageJson);
end;
}
}
part("Agent Available Tools"; "Agent Available Tools Part")
{
Caption = 'What tools the agent had access to';
Enabled = false;
AboutTitle = 'What tools the agent had available for the current page and context';
AboutText = 'Lists the tools that were available to the agent at this point. The set of available tools may change over time; do not rely on this list being exhaustive or permanent in instructions.';
Visible = IsAvailableToolsVisible and IsAgentAction;
}
part("Agent Memorized Data"; "Agent Memorized Data Part")
{
Caption = 'What data the agent memorized';
AboutTitle = 'What data the agent memorized';
AboutText = 'Lists the key-value data that the agent had memorized as part of the current task at this point.';
Visible = IsMemorizedDataVisible and IsAgentAction;
}
part(EarlierMessagesPart; "Agent Task Message ListPart")
{
Caption = 'What messages the agent had access to';
SubPageLink = "Task ID" = field("Task ID");
AboutTitle = 'What messages the agent had access to';
AboutText = 'Lists the messages related to the task the agent had access to before taking a decision.';
Enabled = false;
Visible = IsEarlierMessagesPartVisible;
}
}
area(FactBoxes)
{
part(TaskContext; "Agent Task Context Part")
{
ApplicationArea = All;
Caption = 'Task context';
AboutTitle = 'Context information about the task and agent';
AboutText = 'Shows context information such as the agent name, task ID, and company name.';
SubPageLink = ID = field("Task ID");
}
part(PageStack; "Agent PageStack Part")
{
Caption = 'Page stack';
AboutTitle = 'What pages were open below';
AboutText = 'Shows the pages that were opened at the time of the log entry.';
Visible = IsCurrentPageStackVisible;
}
part(TaskPageSettings; "Agent Task Page Settings Part")
{
Caption = 'Task and page settings';
AboutTitle = 'Task and page settings';
AboutText = 'Shows the settings of the page at the time of the log entry.';
Visible = IsTaskPageSettingsVisible;
}
}
}
trigger OnAfterGetCurrRecord()
begin
UpdateControls();
end;
local procedure UpdateControls()
var
AgentTaskLogEntryRecord: Record "Agent Task Log Entry";
AgentTaskLogEntry: Codeunit "Agent Task Log Entry";
AgentTaskImpl: Codeunit "Agent Task Impl.";
ContentInStream: InStream;
begin
LogEntryDetailsTxt := AgentTaskImpl.GetDetailsForAgentTaskLogEntry(Rec);
SetIsAgentAction();
if not MemoryEntry.Get(Rec."Task ID", Rec."Memory Entry ID") then begin
MemoryEntryDetailsTxt := '';
ClearPartsAndVariables();
exit;
end;
MemoryEntry.CalcFields(Details);
MemoryEntry.Details.CreateInStream(ContentInStream, AgentTaskLogEntry.GetDefaultEncoding());
ContentInStream.Read(MemoryEntryDetailsTxt);
SetAgentName();
ParseDetails();
GetPageContext();
if Rec.Id <> GlobalCurrentID then begin
CurrPage.InputMessagePart.Page.DisplayInputMessageFor(MemoryEntry.ID);
CurrPage.OutputMessagePart.Page.DisplayOutputMessageFor(MemoryEntry.ID);
IsEarlierMessagesPartVisible := CurrPage.EarlierMessagesPart.Page.DisplayMessagesEarlierThan(MemoryEntry.ID);
CurrPage.LogsPart.Page.SetEntryFilter(MemoryEntry.ID);
GlobalCurrentID := Rec.Id;
CurrPage.Update(false);
end;
AgentTaskLogEntryRecord.SetRange("Task ID", Rec."Task ID");
AgentTaskLogEntryRecord.SetRange("Memory Entry ID", MemoryEntry.ID);
IsLogPageVisible := AgentTaskLogEntryRecord.Count() > 1;
end;
local procedure ParseDetails()
var
RootObj: JsonObject;
begin
if not RootObj.ReadFrom(MemoryEntryDetailsTxt) then
exit;
IsSuccess := RootObj.Contains(SuccessLbl)
? Format(RootObj.GetBoolean(SuccessLbl, true))
: '';
end;
local procedure SetAgentName()
var
Agent: Record Agent;
AgentTaskImpl: Codeunit "Agent Task Impl.";
begin
if not AgentTaskImpl.TryGetAgentRecordFromTaskId(Rec."Task ID", Agent) then begin
AgentName := '';
exit;
end;
AgentName := Agent."Display Name";
end;
local procedure SetIsAgentAction()
var
User: Record User;
Default: Boolean;
begin
Default := false;
case Rec.Type of
// Operations always performed by a user.
Rec.Type::"Input Message",
Rec.Type::Resume,
Rec.Type::"User Intervention":
IsAgentAction := false;
// Operations always performed by the agent.
Rec.Type::"Page Operation",
Rec.Type::"Output Message",
Rec.Type::"Output Message Draft",
Rec.Type::"User Intervention Request":
IsAgentAction := true;
// Operations performed by a user or the agent.
Rec.Type::Stop:
IsAgentAction := User.Get(Rec."User Security ID")
? User."License Type" = User."License Type"::Agent
: Default;
// By default, consider it was a user action.
else
IsAgentAction := Default;
end;
end;
local procedure GetPageContext()
var
TempAvailableToolsRecords: Record "Agent JSON Buffer" temporary;
TempPageStacksRecords: Record "Agent JSON Buffer" temporary;
TempMemorizedDataRecords: Record "Agent JSON Buffer" temporary;
AgentTaskLogEntry: Codeunit "Agent Task Log Entry";
AgentSystemPermissionsImpl: Codeunit "Agent System Permissions Impl.";
Root: JsonObject;
TaskPageContextObj: JsonObject;
RawSerializedPageJson: Text;
begin
ContextTxt := AgentTaskLogEntry.ReadContext(Rec);
if ContextTxt = '' then
// Fallback to memory entry context.
ContextTxt := AgentTaskLogEntry.ReadContext(MemoryEntry);
IsSerializedPageVisible := ContextTxt <> '';
if not Root.ReadFrom(ContextTxt) then begin
ClearPartsAndVariables();
exit;
end;
RawSerializedPageJson := Root.GetText(SerializedPageLbl, true);
if RawSerializedPageJson <> '' then
SerializedPageJson := AgentSystemPermissionsImpl.CurrentUserHasTroubleshootAllAgents()
? AgentTaskLogEntry.FormatJsonTextForRichContent(RawSerializedPageJson)
: AgentTroubleshooterMissingPermissionTxt
else
IsSerializedPageVisible := false;
IsDecisionTxt := Root.Contains(IsDecisionPointLbl)
? Format(Root.GetBoolean(IsDecisionPointLbl, true))
: Format(false);
AgentTaskLogEntry.ExtractPageStack(TempPageStacksRecords, Root);
IsCurrentPageStackVisible := TempPageStacksRecords.Count() > 0;
CurrPage.PageStack.Page.SetData(TempPageStacksRecords);
CurrPage.PageStack.Page.Update();
AgentTaskLogEntry.ExtractAvailableTools(TempAvailableToolsRecords, Root);
IsAvailableToolsVisible := TempAvailableToolsRecords.Count() > 0;
CurrPage."Agent Available Tools".Page.SetData(TempAvailableToolsRecords);
CurrPage."Agent Available Tools".Page.Update();
AgentTaskLogEntry.ExtractMemorizedData(TempMemorizedDataRecords, Root);
IsMemorizedDataVisible := TempMemorizedDataRecords.Count() > 0;
CurrPage."Agent Memorized Data".Page.SetData(TempMemorizedDataRecords);
CurrPage."Agent Memorized Data".Page.Update();
if (not Root.Contains(TaskPageContextLbl)) then
IsTaskPageSettingsVisible := false
else begin
IsTaskPageSettingsVisible := true;
TaskPageContextObj := Root.GetObject(TaskPageContextLbl, true);
CurrPage.TaskPageSettings.Page.SetData(TaskPageContextObj);
CurrPage.TaskPageSettings.Page.Update();
end;
end;
local procedure ClearPartsAndVariables()
begin
IsDecisionTxt := Format(false);
IsLogPageVisible := false;
IsSerializedPageVisible := false;
IsEarlierMessagesPartVisible := false;
CurrPage.PageStack.Page.ClearData();
CurrPage.PageStack.Page.Update();
IsCurrentPageStackVisible := false;
CurrPage."Agent Available Tools".Page.ClearData();
CurrPage."Agent Available Tools".Page.Update();
IsAvailableToolsVisible := false;
CurrPage."Agent Memorized Data".Page.ClearData();
CurrPage."Agent Memorized Data".Page.Update();
IsMemorizedDataVisible := false;
CurrPage.TaskPageSettings.Page.ClearData();
CurrPage.TaskPageSettings.Page.Update();
IsTaskPageSettingsVisible := false;
end;
var
MemoryEntry: Record "Agent Task Memory Entry";
AgentTroubleshooterMissingPermissionTxt: Label 'Only users who are assigned the ''Troubleshoot All Agents'' permission can view page snapshot data.';
ContextTxt: Text;
MemoryEntryDetailsTxt: Text;
LogEntryDetailsTxt: Text;
AgentName: text;
SerializedPageJson: text;
IsDecisionTxt: Text;
IsSuccess: Text;
IsAgentAction: Boolean;
IsAvailableToolsVisible: Boolean;
IsEarlierMessagesPartVisible: Boolean;
IsSerializedPageVisible: Boolean;
IsTaskPageSettingsVisible: Boolean;
IsCurrentPageStackVisible: Boolean;
IsMemorizedDataVisible: Boolean;
IsLogPageVisible: Boolean;
GlobalCurrentID: Integer;
SerializedPageLbl: Label 'serializedPage', Locked = true;
IsDecisionPointLbl: Label 'isDecisionPoint', Locked = true;
TaskPageContextLbl: Label 'taskPageContext', Locked = true;
SuccessLbl: Label 'success', Locked = true;
PageCaptionLbl: Label 'Log %1 - %2', Comment = '%1 is the id, and %2 is the description of it.';
}