diff --git a/src/System Application/App/Agent/Interaction/Internal/AgentTaskImpl.Codeunit.al b/src/System Application/App/Agent/Interaction/Internal/AgentTaskImpl.Codeunit.al index e6c5e56092..4b211a6a4d 100644 --- a/src/System Application/App/Agent/Interaction/Internal/AgentTaskImpl.Codeunit.al +++ b/src/System Application/App/Agent/Interaction/Internal/AgentTaskImpl.Codeunit.al @@ -206,6 +206,17 @@ codeunit 4300 "Agent Task Impl." exit((AgentTask.Status = AgentTask.Status::"Stopped by User") or (AgentTask.Status = AgentTask.Status::"Stopped by System")); end; + internal procedure TryGetAgentRecordFromTaskId(TaskId: Integer; var Agent: Record Agent): Boolean + var + AgentTask: Record "Agent Task"; + begin + if AgentTask.Get(TaskId) then + if Agent.Get(AgentTask."Agent User Security ID") then + exit(true); + + exit(false); + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"System Action Triggers", GetAgentTaskMessagePageId, '', true, true)] local procedure OnGetAgentTaskMessagePageId(var PageId: Integer) begin diff --git a/src/System Application/App/Agent/Interaction/Internal/AgentTaskLogEntryList.Page.al b/src/System Application/App/Agent/Interaction/Internal/AgentTaskLogEntryList.Page.al index 45810ae418..f58031cd55 100644 --- a/src/System Application/App/Agent/Interaction/Internal/AgentTaskLogEntryList.Page.al +++ b/src/System Application/App/Agent/Interaction/Internal/AgentTaskLogEntryList.Page.al @@ -63,6 +63,20 @@ page 4303 "Agent Task Log Entry List" field(Description; Rec.Description) { Caption = 'Description'; + + trigger OnDrillDown() + begin + Message(Rec.Description); + end; + } + field(Reason; Rec.Reason) + { + Caption = 'Reason'; + + trigger OnDrillDown() + begin + Message(Rec.Reason); + end; } field(Details; DetailsTxt) { @@ -75,6 +89,28 @@ page 4303 "Agent Task Log Entry List" end; } } + fixed(DisclaimerGroup) + { + group(Left) + { + ShowCaption = false; + label(Empty) + { + ApplicationArea = All; + Caption = '', Locked = true; + } + } + group(Right) + { + ShowCaption = false; + label(Disclaimer) + { + ApplicationArea = All; + Caption = 'AI-generated content may be incorrect.'; + Style = Subordinate; + } + } + } } area(FactBoxes) @@ -97,6 +133,9 @@ page 4303 "Agent Task Log Entry List" actionref(Refresh_Promoted; Refresh) { } + actionref(Feedback_Promoted; Feedback) + { + } } area(Creation) { @@ -111,6 +150,24 @@ page 4303 "Agent Task Log Entry List" CurrPage.Update(false); end; } + action(Feedback) + { + ApplicationArea = All; + Caption = 'Give Feedback'; + ToolTip = 'Tell us what you think about the agent and suggest new features or improvements.'; + Image = Comment; + Enabled = IsFeedbackActionEnabled; + Visible = IsFeedbackActionEnabled; + + trigger OnAction() + var + AgentUserFeedback: Codeunit "Agent User Feedback"; + ContextProperties: Dictionary of [Text, Text]; + begin + ContextProperties := AgentUserFeedback.InitializeAgentTaskContext(Rec."Task ID"); + AgentUserFeedback.RequestFeedback('Agent Task Log Entries', ContextProperties); + end; + } } } @@ -126,20 +183,27 @@ page 4303 "Agent Task Log Entry List" local procedure UpdateControls() var + Agent: Record Agent; AgentTaskImpl: Codeunit "Agent Task Impl."; begin DetailsTxt := AgentTaskImpl.GetDetailsForAgentTaskLogEntry(Rec); case Rec.Level of Rec.Level::Error: - TypeStyle := 'Unfavorable'; + TypeStyle := Format(PageStyle::Unfavorable); Rec.Level::Warning: - TypeStyle := 'Ambiguous'; + TypeStyle := Format(PageStyle::Ambiguous); else - TypeStyle := 'Standard'; + TypeStyle := Format(PageStyle::Standard); end; + + if AgentTaskImpl.TryGetAgentRecordFromTaskId(Rec."Task ID", Agent) then + IsFeedbackActionEnabled := Agent."Publisher Type" <> Agent."Publisher Type"::"Third Party" + else + IsFeedbackActionEnabled := false end; var + IsFeedbackActionEnabled: Boolean; DetailsTxt: Text; TypeStyle: Text; } diff --git a/src/System Application/App/Agent/Interaction/Internal/AgentUserFeedback.Codeunit.al b/src/System Application/App/Agent/Interaction/Internal/AgentUserFeedback.Codeunit.al new file mode 100644 index 0000000000..678b78fcf4 --- /dev/null +++ b/src/System Application/App/Agent/Interaction/Internal/AgentUserFeedback.Codeunit.al @@ -0,0 +1,104 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +using System.Feedback; + +codeunit 4329 "Agent User Feedback" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + // The values below align with the existing feature and context properties from the timeline. + var + AgentUserSecurityIdTok: Label 'Copilot.Agents.AgentId', Locked = true; + AgentMetadataProviderTok: Label 'Copilot.Agents.AgentTypeId', Locked = true; + AgentTaskIdTok: Label 'Copilot.Agents.TaskId', Locked = true; + AgentFeatureAreaTok: Label 'Copilot', Locked = true; + AgentFeatureDisplayNameTok: Label 'Copilot', Locked = true; + + // The values below are not used by the timeline. + var + AgentTaskLogEntryIdTok: Label 'Copilot.Agents.TaskLogEntryId', Locked = true; + AgentTaskLogEntryTypeTok: Label 'Copilot.Agents.TaskLogEntryType', Locked = true; + + + [Scope('OnPrem')] + procedure GetAgentMetadataProviderTok(): Text + begin + exit(AgentMetadataProviderTok); + end; + + [Scope('OnPrem')] + procedure GetAgentUserSecurityIdTok(): Text + begin + exit(AgentUserSecurityIdTok); + end; + + [Scope('OnPrem')] + procedure GetAgentTaskIdTok(): Text + begin + exit(AgentTaskIdTok); + end; + + [Scope('OnPrem')] + procedure GetAgentTaskLogEntryIdTok(): Text + begin + exit(AgentTaskLogEntryIdTok); + end; + + [Scope('OnPrem')] + procedure GetAgentTaskLogEntryTypeTok(): Text + begin + exit(AgentTaskLogEntryTypeTok); + end; + + [Scope('OnPrem')] + procedure InitializeAgentContext(AgentMetadataProvider: Enum "Agent Metadata Provider"; AgentUserSecurityID: Guid) Context: Dictionary of [Text, Text] + begin + Context.Add(AgentMetadataProviderTok, Format(AgentMetadataProvider.AsInteger())); + Context.Add(AgentUserSecurityIdTok, Format(AgentUserSecurityID)); + end; + + [Scope('OnPrem')] + procedure InitializeAgentTaskContext(TaskId: BigInteger) Context: Dictionary of [Text, Text] + var + Agent: Record Agent; + AgentTaskImpl: Codeunit "Agent Task Impl."; + begin + if not (AgentTaskImpl.TryGetAgentRecordFromTaskId(TaskId, Agent)) then + exit; + + Context := InitializeAgentContext(Agent."Agent Metadata Provider", Agent."User Security ID"); + Context.Add(AgentTaskIdTok, Format(TaskId)); + end; + + [Scope('OnPrem')] + procedure RequestFeedback(FeatureName: Text; Context: Dictionary of [Text, Text]) + var + MicrosoftUserFeedback: Codeunit "Microsoft User Feedback"; + EmptyContextFiles: Dictionary of [Text, Text]; + FeedbackType: Text; + CopilotThumbsUpTok: Label 'Copilot.ThumbsUp', Locked = true; + CopilotThumbsDownTok: Label 'Copilot.ThumbsDown', Locked = true; + FeedbackTypeTok: Label 'Feedback.Type', Locked = true; + begin + MicrosoftUserFeedback.SetIsAIFeedback(true); + + if Context.ContainsKey(FeedbackTypeTok) then + FeedbackType := Context.Get(FeedbackTypeTok); + + case FeedbackType of + CopilotThumbsUpTok: + MicrosoftUserFeedback.RequestLikeFeedback(FeatureName, AgentFeatureAreaTok, AgentFeatureDisplayNameTok, EmptyContextFiles, Context); + CopilotThumbsDownTok: + MicrosoftUserFeedback.RequestDislikeFeedback(FeatureName, AgentFeatureAreaTok, AgentFeatureDisplayNameTok, EmptyContextFiles, Context); + else + MicrosoftUserFeedback.RequestFeedback(FeatureName, AgentFeatureAreaTok, AgentFeatureDisplayNameTok, EmptyContextFiles, Context); + end; + end; +} \ No newline at end of file diff --git a/src/System Application/App/Agent/app.json b/src/System Application/App/Agent/app.json index 5b97c7e1ba..90bffba988 100644 --- a/src/System Application/App/Agent/app.json +++ b/src/System Application/App/Agent/app.json @@ -68,6 +68,12 @@ "name": "Data Compression", "publisher": "Microsoft", "version": "27.4.0.0" + }, + { + "id": "f7964d32-7685-400f-8297-4bc17d0aab0e", + "name": "Microsoft User Feedback", + "publisher": "Microsoft", + "version": "27.4.0.0" } ], "propagateDependencies": true,