From cad87447481c70a37ff11d50ed496cc5f2d95c53 Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Sun, 23 Apr 2023 08:26:59 -0400 Subject: [PATCH 1/6] tools --- .../tools/classes/Base64EncoderAgentTool.cls | 25 +++++ .../Base64EncoderAgentTool.cls-meta.xml | 5 + .../main/tools/classes/ChatterAgentTool.cls | 104 ++++++++++++++++++ .../classes/ChatterAgentTool.cls-meta.xml | 5 + .../tools/classes/FileCreationAgentTool.cls | 50 +++++++++ .../FileCreationAgentTool.cls-meta.xml | 5 + .../tools/classes/MergeRecordsAgentTool.cls | 0 .../MergeRecordsAgentTool.cls-meta.xml | 5 + .../tools/classes/SObjectSearchAgentTool.cls | 78 +++++++++++++ .../SObjectSearchAgentTool.cls-meta.xml | 5 + 10 files changed, 282 insertions(+) create mode 100644 force-app/main/tools/classes/Base64EncoderAgentTool.cls create mode 100644 force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml create mode 100644 force-app/main/tools/classes/ChatterAgentTool.cls create mode 100644 force-app/main/tools/classes/ChatterAgentTool.cls-meta.xml create mode 100644 force-app/main/tools/classes/FileCreationAgentTool.cls create mode 100644 force-app/main/tools/classes/FileCreationAgentTool.cls-meta.xml create mode 100644 force-app/main/tools/classes/MergeRecordsAgentTool.cls create mode 100644 force-app/main/tools/classes/MergeRecordsAgentTool.cls-meta.xml create mode 100644 force-app/main/tools/classes/SObjectSearchAgentTool.cls create mode 100644 force-app/main/tools/classes/SObjectSearchAgentTool.cls-meta.xml diff --git a/force-app/main/tools/classes/Base64EncoderAgentTool.cls b/force-app/main/tools/classes/Base64EncoderAgentTool.cls new file mode 100644 index 0000000..62709a0 --- /dev/null +++ b/force-app/main/tools/classes/Base64EncoderAgentTool.cls @@ -0,0 +1,25 @@ +public class Base64EncoderAgentTool implements IAgentTool { + + public String getDescription() { + return 'Base64 encodes the input data'; + } + + public Map getParameters() { + return new Map({ + 'data' => 'The data to be base64 encoded' + }); + } + + public String execute(Map args) { + if (String.isEmpty(args.get('data'))) { + throw new Agent.ActionRuntimeException('missing required parameter: data'); + } + return base64Encode(args.get('data')); + } + + private String base64Encode(String data) { + Blob inputBlob = Blob.valueOf(data); + String base64EncodedData = EncodingUtil.base64Encode(inputBlob); + return base64EncodedData; + } + } \ No newline at end of file diff --git a/force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml b/force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/ChatterAgentTool.cls b/force-app/main/tools/classes/ChatterAgentTool.cls new file mode 100644 index 0000000..979f2aa --- /dev/null +++ b/force-app/main/tools/classes/ChatterAgentTool.cls @@ -0,0 +1,104 @@ +public class ChatterAgentTool implements IAgentTool { + public String getDescription() { + return 'Chatter Agent Tool for managing Chatter posts'; + } + + public Map getParameters() { + return new Map{ + 'operation' => 'The action to be performed: insert, delete, retrieve, update, or upsert on the Chatter post', + 'Id' => 'The unique identifier of the Chatter post to be retrieved, updated, or deleted', + 'parentId' => 'The unique identifier of the parent record, such as the Account record Id for a post on the Account record page', + 'title' => 'The title of the feed item; for LinkPost type, this is the link name; can only be updated on posts of type QuestionPost', + 'body' => 'The main text content of the Chatter post', + 'isRichText' => 'Indicates whether the post body contains rich text formatting: true or false', + 'linkUrl' => 'The web address for LinkPost type.', + 'visibility' => 'The post visibility level: AllUsers (visible to everyone) or InternalUsers (visible only to internal users). Optional. For record posts, Visibility is set to InternalUsers for all internal users by default.', + 'type' => 'The category of the Chatter post: LinkPost, QuestionPost, or TextPost. Usually will be TextPost', + 'lastEditById' => 'The unique identifier of the Salesforce User who made the most recent edit. Optional', + 'lastEditDate' => 'The date and time of the most recent edit, as a DateTime string. Optional.', + 'revision' => 'The version number of the Chatter post as an Integer. Optional.', + 'status' => 'The current state of the Chatter post: Published or PendingReview. The value Published means publicly available while PendingReview means awaiting approval.' + } + } + + public String execute(Map args) { + String operation = args.get('operation'); + if (String.isEmpty(operation)) { + throw new Agent.ActionRuntimeException('Missing required parameter: operation'); + } + operation = operation.toLowerCase(); + switch on operation { + when 'delete' { + return deletePost(args.get('Id')); + } + when 'retrieve' { + return retrievePost(args.get('Id')); + } + when 'insert','update','upsert' { + return insertUpdateUpsert(args); + } + when else { + throw new Agent.ActionRuntimeException('Invalid operation: ' + operation); + } + } + } + + private Sobject setFeedItemFields(Sobject sobj, Map args) { + for (String key : args.keySet()) { + if (args.get(key) != null) { + if (key == 'isRichText') { + sobj.put(key, Boolean.valueOf(args.get(key))); + } else if (key == 'lastEditDate') { + sobj.put(key, DateTime.valueOf(args.get(key))); + } else if (key == 'revision') { + sobj.put(key, Integer.valueOf(args.get(key))); + } else { + sobj.put(key, args.get(key)); + } + } + } + return sobj; + } + + private String retrievePost(String Id) { + FeedItem post = [SELECT Id, parentId, Body, isRichText, linkUrl, visibility, type CreatedDate, LastEditById, LastEditDate, Revision, Status FROM FeedItem WHERE Id = :Id]; + return JSON.serialize(post); + } + + private String deletePost(String Id) { + FeedItem post = [SELECT Id FROM FeedItem WHERE Id = :Id]; + delete post; + return 'Post deleted with Id: ' + id; + } + + private String insertUpdateUpsert(Map args) { + String operation = args.get('operation'); + if(operation == 'insert') { + if (String.isEmpty(args.get('parentId'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: parentId'); + } + if (String.isEmpty(args.get('body'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: body'); + } + } else if (operation == 'update' || operation == 'upsert') { + if (String.isEmpty(args.get('Id'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: Id'); + } + } + FeedItem post = new FeedItem(); + if (operation == 'update' || operation == 'upsert') { + post.Id = args.get('Id'); + } + post = setFeedItemFields(post, args); + if(operation == 'insert') { + insert post; + return 'Post inserted with Id: ' + post.Id; + } else if(operation == 'update') { + update post; + return 'Post updated with Id: ' + post.Id; + } else if (operation == 'upsert') { + upsert post; + return 'Post upserted with Id: ' + post.Id; + } + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/ChatterAgentTool.cls-meta.xml b/force-app/main/tools/classes/ChatterAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/ChatterAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/FileCreationAgentTool.cls b/force-app/main/tools/classes/FileCreationAgentTool.cls new file mode 100644 index 0000000..1549601 --- /dev/null +++ b/force-app/main/tools/classes/FileCreationAgentTool.cls @@ -0,0 +1,50 @@ +public class FileCreationAgentTool implements IAgentTool { + public String getDescription() { + return 'Create Salesforce files and optionally link them to Salesforce records'; + } + + public Map getParameters() { + return new Map({ + 'fileName' => 'The name of the file to be created', + 'fileContent' => 'The string content of the file', + 'recordId' => 'The Salesforce record Id to which the file should be linked (optional)' + }); + } + + private String base64Encode(String data) { + Blob inputBlob = Blob.valueOf(data); + String base64EncodedData = EncodingUtil.base64Encode(inputBlob); + return base64EncodedData; + } + + public String execute(Map args) { + if (String.isEmpty(args.get('fileName'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: fileName'); + } + + if (String.isEmpty(args.get('fileContent'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: fileContent'); + } + + String fileName = args.get('fileName'); + String fileContent = args.get('fileContent'); + String recordId = args.get('recordId'); + + ContentVersion cv = new ContentVersion(); + cv.Title = fileName; + cv.PathOnClient = fileName; + cv.VersionData = base64Encode(fileContent); + cv.IsMajorVersion = true; + insert cv; + + if (!String.isEmpty(recordId)) { + ContentDocumentLink cdl = new ContentDocumentLink(); + cdl.LinkedEntityId = recordId; + cdl.ContentDocumentId = cv.Id; + cdl.shareType = 'V'; + insert cdl; + } + + return 'File created with Id: ' + conDocId; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/FileCreationAgentTool.cls-meta.xml b/force-app/main/tools/classes/FileCreationAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/FileCreationAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/MergeRecordsAgentTool.cls b/force-app/main/tools/classes/MergeRecordsAgentTool.cls new file mode 100644 index 0000000..e69de29 diff --git a/force-app/main/tools/classes/MergeRecordsAgentTool.cls-meta.xml b/force-app/main/tools/classes/MergeRecordsAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/MergeRecordsAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/SObjectSearchAgentTool.cls b/force-app/main/tools/classes/SObjectSearchAgentTool.cls new file mode 100644 index 0000000..97a3cab --- /dev/null +++ b/force-app/main/tools/classes/SObjectSearchAgentTool.cls @@ -0,0 +1,78 @@ +public class KnowledgeArticleAgentTool implements IAgentTool { + public String getDescription() { + return 'Returns a list of SObject records or Salesforce Knowledge articles whose names or titles match the user’s search query string'; + } + + public Map getParameters() { + return new Map({ + 'searchText' => 'The text to search for in Knowledge Articles', + 'nbResult' => 'The maximum number of results to return', + 'objectType' => 'The SObject to search: KnowledgeArticleVersion, Account, Contact, etc. Use KnowledgeArticleVersion for Knowledge Base Articles.', + 'language' => 'For Knowledge Base Articles, The language to filter the articles by: en_US, es, fr, etc', + 'publishStatus' => 'For Knowledge Base Articles, The publishing status of the articles to filter: Online, Draft, or Archived' + }); + } + + public String execute(Map args) { + String searchText = args.get('searchText'); + if (String.isEmpty(searchText)) { + throw new Agent.ActionRuntimeException('missing required parameter: searchText'); + } + + String language = args.get('language'); + if (String.isEmpty(language)) { + throw new Agent.ActionRuntimeException('missing required parameter: language'); + } + + String objectType = args.get('objectType'); + if (String.isEmpty(objectType)) { + throw new Agent.ActionRuntimeException('missing required parameter: objectType'); + } + + String publishStatus = args.get('publishStatus'); + if (String.isEmpty(publishStatus)) { + throw new Agent.ActionRuntimeException('missing required parameter: publishStatus'); + } + + String nbResultStr = args.get('nbResult'); + if (String.isEmpty(nbResultStr)) { + throw new Agent.ActionRuntimeException('missing required parameter: nbResult'); + } + + Integer nbResult; + try { + nbResult = Integer.valueOf(nbResultStr); + } catch (Exception e) { + throw new Agent.ActionRuntimeException('invalid value for parameter: nbResult'); + } + + List suggestionResults = searchKnowledgeArticles(searchText, objectType, language, publishStatus, nbResult); + return formatResults(suggestionResults); + } + + private List searchKnowledgeArticles(String searchText, String objectType, String language, String publishStatus, Integer nbResult) { + Search.SuggestionOption options = new Search.SuggestionOption(); + if (objectType == 'KnowledgeArticleVersion') { + Search.KnowledgeSuggestionFilter filters = new Search.KnowledgeSuggestionFilter(); + filters.setLanguage(language); + filters.setPublishStatus(publishStatus); + options.setFilter(filters); + } + options.setLimit(nbResult); + return Search.suggest(searchText, objectType, options); + } + + private String formatResults(List suggestionResults) { + String result = 'Results:\n'; + for (Search.Suggestion suggestion : suggestionResults) { + if(suggestion.getSobject().isSet('Title')) { //KnowledgeArticleVersion + result += '- ' + suggestion.getSobject().get('Title') + ' (' + suggestion.getSobject().get('Id') + ')\n'; + } else if(suggestion.getSobject().isSet('Name')) {// Other SObject + result += '- ' + suggestion.getSobject().get('Name') + ' (' + suggestion.getSobject().get('Id') + ')\n'; + } else { // Should not happen + result += '- ' + suggestion.getSobject().get('Id') + '\n'; + } + } + return result; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/SObjectSearchAgentTool.cls-meta.xml b/force-app/main/tools/classes/SObjectSearchAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/SObjectSearchAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file From a8484ee6a1a0ed5163d760f689b41efdf5f3225d Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Sun, 23 Apr 2023 08:49:14 -0400 Subject: [PATCH 2/6] tools --- .../tools/classes/Base64EncoderAgentTool.cls | 4 +- .../main/tools/classes/ChatterAgentTool.cls | 2 +- .../tools/classes/FileCreationAgentTool.cls | 4 +- .../tools/classes/MergeRecordsAgentTool.cls | 49 +++++++++++++++++++ .../tools/classes/SObjectSearchAgentTool.cls | 34 ++++++------- 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/force-app/main/tools/classes/Base64EncoderAgentTool.cls b/force-app/main/tools/classes/Base64EncoderAgentTool.cls index 62709a0..cc7dab1 100644 --- a/force-app/main/tools/classes/Base64EncoderAgentTool.cls +++ b/force-app/main/tools/classes/Base64EncoderAgentTool.cls @@ -5,9 +5,9 @@ public class Base64EncoderAgentTool implements IAgentTool { } public Map getParameters() { - return new Map({ + return new Map{ 'data' => 'The data to be base64 encoded' - }); + }; } public String execute(Map args) { diff --git a/force-app/main/tools/classes/ChatterAgentTool.cls b/force-app/main/tools/classes/ChatterAgentTool.cls index 979f2aa..8755bd5 100644 --- a/force-app/main/tools/classes/ChatterAgentTool.cls +++ b/force-app/main/tools/classes/ChatterAgentTool.cls @@ -18,7 +18,7 @@ public class ChatterAgentTool implements IAgentTool { 'lastEditDate' => 'The date and time of the most recent edit, as a DateTime string. Optional.', 'revision' => 'The version number of the Chatter post as an Integer. Optional.', 'status' => 'The current state of the Chatter post: Published or PendingReview. The value Published means publicly available while PendingReview means awaiting approval.' - } + }; } public String execute(Map args) { diff --git a/force-app/main/tools/classes/FileCreationAgentTool.cls b/force-app/main/tools/classes/FileCreationAgentTool.cls index 1549601..07a70a2 100644 --- a/force-app/main/tools/classes/FileCreationAgentTool.cls +++ b/force-app/main/tools/classes/FileCreationAgentTool.cls @@ -4,11 +4,11 @@ public class FileCreationAgentTool implements IAgentTool { } public Map getParameters() { - return new Map({ + return new Map{ 'fileName' => 'The name of the file to be created', 'fileContent' => 'The string content of the file', 'recordId' => 'The Salesforce record Id to which the file should be linked (optional)' - }); + }; } private String base64Encode(String data) { diff --git a/force-app/main/tools/classes/MergeRecordsAgentTool.cls b/force-app/main/tools/classes/MergeRecordsAgentTool.cls index e69de29..0e13fb6 100644 --- a/force-app/main/tools/classes/MergeRecordsAgentTool.cls +++ b/force-app/main/tools/classes/MergeRecordsAgentTool.cls @@ -0,0 +1,49 @@ +public class MergeRecordsAgentTool implements IAgentTool { + + public String getDescription() { + return 'Merge records of the same sObject type'; + } + + public Map getParameters() { + return new Map{ + 'sObjectType' => 'The sObject type to merge (e.g., Account, Contact, Lead, Case)', + 'masterRecordId' => 'The ID of the master record to merge into', + 'mergeRecordIds' => 'A comma-separated list of up to two record IDs to merge with the master record' + }; + } + + public String execute(Map args) { + if (String.isEmpty(args.get('sObjectType')) || String.isEmpty(args.get('masterRecordId')) || String.isEmpty(args.get('mergeRecordIds'))) { + throw new Agent.ActionRuntimeException('missing required parameters: sObjectType, masterRecordId, mergeRecordIds'); + } + + String sObjectType = args.get('sObjectType'); + Id masterRecordId = Id.valueOf(args.get('masterRecordId')); + List mergeRecordIdStrings = args.get('mergeRecordIds').split(','); + List mergeRecordIds = new List(); + for (String mergeRecordIdString : mergeRecordIdStrings) { + mergeRecordIds.add(Id.valueOf(mergeRecordIdString)); + } + + SObject masterRecord = Database.query('SELECT Id FROM ' + sObjectType + ' WHERE Id = :masterRecordId'); + List mergeRecords = Database.query('SELECT Id FROM ' + sObjectType + ' WHERE Id IN :mergeRecordIds'); + + if (mergeRecords.size() > 2) { + throw new Agent.ActionRuntimeException('You can only merge up to two records with the master record'); + } + + Database.MergeResult[] mergeResults = Database.merge(masterRecord, mergeRecords, false); + + for (Database.MergeResult mergeResult : mergeResults) { + if (!mergeResult.isSuccess()) { + String errorMessage = 'Failed to merge records: '; + for (Database.Error error : mergeResult.getErrors()) { + errorMessage += error.getMessage() + '. '; + } + throw new Agent.ActionRuntimeException(errorMessage); + } + } + + return 'Records merged successfully'; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/SObjectSearchAgentTool.cls b/force-app/main/tools/classes/SObjectSearchAgentTool.cls index 97a3cab..67ebd66 100644 --- a/force-app/main/tools/classes/SObjectSearchAgentTool.cls +++ b/force-app/main/tools/classes/SObjectSearchAgentTool.cls @@ -4,13 +4,13 @@ public class KnowledgeArticleAgentTool implements IAgentTool { } public Map getParameters() { - return new Map({ + return new Map{ 'searchText' => 'The text to search for in Knowledge Articles', 'nbResult' => 'The maximum number of results to return', 'objectType' => 'The SObject to search: KnowledgeArticleVersion, Account, Contact, etc. Use KnowledgeArticleVersion for Knowledge Base Articles.', 'language' => 'For Knowledge Base Articles, The language to filter the articles by: en_US, es, fr, etc', 'publishStatus' => 'For Knowledge Base Articles, The publishing status of the articles to filter: Online, Draft, or Archived' - }); + }; } public String execute(Map args) { @@ -46,11 +46,6 @@ public class KnowledgeArticleAgentTool implements IAgentTool { throw new Agent.ActionRuntimeException('invalid value for parameter: nbResult'); } - List suggestionResults = searchKnowledgeArticles(searchText, objectType, language, publishStatus, nbResult); - return formatResults(suggestionResults); - } - - private List searchKnowledgeArticles(String searchText, String objectType, String language, String publishStatus, Integer nbResult) { Search.SuggestionOption options = new Search.SuggestionOption(); if (objectType == 'KnowledgeArticleVersion') { Search.KnowledgeSuggestionFilter filters = new Search.KnowledgeSuggestionFilter(); @@ -59,18 +54,21 @@ public class KnowledgeArticleAgentTool implements IAgentTool { options.setFilter(filters); } options.setLimit(nbResult); - return Search.suggest(searchText, objectType, options); - } - - private String formatResults(List suggestionResults) { + + Search.SuggestionResults suggestionResults = Search.suggest(searchText, objectType, options); + String result = 'Results:\n'; - for (Search.Suggestion suggestion : suggestionResults) { - if(suggestion.getSobject().isSet('Title')) { //KnowledgeArticleVersion - result += '- ' + suggestion.getSobject().get('Title') + ' (' + suggestion.getSobject().get('Id') + ')\n'; - } else if(suggestion.getSobject().isSet('Name')) {// Other SObject - result += '- ' + suggestion.getSobject().get('Name') + ' (' + suggestion.getSobject().get('Id') + ')\n'; - } else { // Should not happen - result += '- ' + suggestion.getSobject().get('Id') + '\n'; + for (Search.SuggestionResult searchResult : suggestionResults.getSuggestionResults()) { + if (objectType == 'KnowledgeArticleVersion') { + if(searchResult.getSobject().isSet('Title')) { //KnowledgeArticleVersion + result += '- ' + searchResult.getSobject().get('Title') + ' (' + searchResult.getSobject().get('Id') + ')\n'; + } + } else { + if(searchResult.getSobject().isSet('Name')) {// Other SObject + result += '- ' + searchResult.getSobject().get('Name') + ' (' + searchResult.getSobject().get('Id') + ')\n'; + } else { // Should not happen + result += '- ' + searchResult.getSobject().get('Id') + '\n'; + } } } return result; From 10dc9d459d18d728831c14c95143e914f5946095 Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Sun, 23 Apr 2023 08:50:41 -0400 Subject: [PATCH 3/6] tools --- .../tools/classes/Base64EncoderAgentTool.cls | 25 ------------------- .../Base64EncoderAgentTool.cls-meta.xml | 5 ---- 2 files changed, 30 deletions(-) delete mode 100644 force-app/main/tools/classes/Base64EncoderAgentTool.cls delete mode 100644 force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml diff --git a/force-app/main/tools/classes/Base64EncoderAgentTool.cls b/force-app/main/tools/classes/Base64EncoderAgentTool.cls deleted file mode 100644 index cc7dab1..0000000 --- a/force-app/main/tools/classes/Base64EncoderAgentTool.cls +++ /dev/null @@ -1,25 +0,0 @@ -public class Base64EncoderAgentTool implements IAgentTool { - - public String getDescription() { - return 'Base64 encodes the input data'; - } - - public Map getParameters() { - return new Map{ - 'data' => 'The data to be base64 encoded' - }; - } - - public String execute(Map args) { - if (String.isEmpty(args.get('data'))) { - throw new Agent.ActionRuntimeException('missing required parameter: data'); - } - return base64Encode(args.get('data')); - } - - private String base64Encode(String data) { - Blob inputBlob = Blob.valueOf(data); - String base64EncodedData = EncodingUtil.base64Encode(inputBlob); - return base64EncodedData; - } - } \ No newline at end of file diff --git a/force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml b/force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml deleted file mode 100644 index 9bbf7b4..0000000 --- a/force-app/main/tools/classes/Base64EncoderAgentTool.cls-meta.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 56.0 - Active - \ No newline at end of file From 0f5e26cc0d16a778a57b9c8411cd3496f9cf008b Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Wed, 26 Apr 2023 11:47:27 -0400 Subject: [PATCH 4/6] tools --- .../lwc/agentChat/__tests__/agentChat.test.js | 25 ---- .../__tests__/agentLogDetails.test.js | 25 ---- .../__tests__/agentLogMonitor.test.js | 25 ---- .../classes/CreateRecordAgentToolTest.cls | 0 .../CreateRecordAgentToolTest.cls-meta.xml | 0 ...terAgentTool.cls => zChatterAgentTool.cls} | 23 ++-- ...eta.xml => zChatterAgentTool.cls-meta.xml} | 0 .../tools/classes/zChatterAgentToolTest.cls | 109 +++++++++++++++++ ...xml => zChatterAgentToolTest.cls-meta.xml} | 0 ...entTool.cls => zFileCreationAgentTool.cls} | 28 ++--- ...ml => zFileCreationAgentTool.cls-meta.xml} | 0 .../classes/zFileCreationAgentToolTest.cls | 94 +++++++++++++++ ...> zFileCreationAgentToolTest.cls-meta.xml} | 0 ....cls => zKnowledgeBaseSearchAgentTool.cls} | 6 +- ...zKnowledgeBaseSearchAgentTool.cls-meta.xml | 5 + .../zKnowledgeBaseSearchAgentToolTest.cls | 43 +++++++ ...wledgeBaseSearchAgentToolTest.cls-meta.xml | 5 + ...entTool.cls => zMergeRecordsAgentTool.cls} | 2 +- .../zMergeRecordsAgentTool.cls-meta.xml | 5 + .../classes/zMergeRecordsAgentToolTest.cls | 111 ++++++++++++++++++ .../zMergeRecordsAgentToolTest.cls-meta.xml | 5 + 21 files changed, 409 insertions(+), 102 deletions(-) delete mode 100644 force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js delete mode 100644 force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js delete mode 100644 force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js create mode 100644 force-app/main/tools/classes/CreateRecordAgentToolTest.cls create mode 100644 force-app/main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml rename force-app/main/tools/classes/{ChatterAgentTool.cls => zChatterAgentTool.cls} (83%) rename force-app/main/tools/classes/{ChatterAgentTool.cls-meta.xml => zChatterAgentTool.cls-meta.xml} (100%) create mode 100644 force-app/main/tools/classes/zChatterAgentToolTest.cls rename force-app/main/tools/classes/{FileCreationAgentTool.cls-meta.xml => zChatterAgentToolTest.cls-meta.xml} (100%) rename force-app/main/tools/classes/{FileCreationAgentTool.cls => zFileCreationAgentTool.cls} (59%) rename force-app/main/tools/classes/{MergeRecordsAgentTool.cls-meta.xml => zFileCreationAgentTool.cls-meta.xml} (100%) create mode 100644 force-app/main/tools/classes/zFileCreationAgentToolTest.cls rename force-app/main/tools/classes/{SObjectSearchAgentTool.cls-meta.xml => zFileCreationAgentToolTest.cls-meta.xml} (100%) rename force-app/main/tools/classes/{SObjectSearchAgentTool.cls => zKnowledgeBaseSearchAgentTool.cls} (90%) create mode 100644 force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml create mode 100644 force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls create mode 100644 force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml rename force-app/main/tools/classes/{MergeRecordsAgentTool.cls => zMergeRecordsAgentTool.cls} (97%) create mode 100644 force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml create mode 100644 force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls create mode 100644 force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml diff --git a/force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js b/force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js deleted file mode 100644 index 84e27ce..0000000 --- a/force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { createElement } from 'lwc'; -import AgentChat from 'c/agentChat'; - -describe('c-agent-chat', () => { - afterEach(() => { - // The jsdom instance is shared across test cases in a single file so reset the DOM - while (document.body.firstChild) { - document.body.removeChild(document.body.firstChild); - } - }); - - it('TODO: test case generated by CLI command, please fill in test logic', () => { - // Arrange - const element = createElement('c-agent-chat', { - is: AgentChat - }); - - // Act - document.body.appendChild(element); - - // Assert - // const div = element.shadowRoot.querySelector('div'); - expect(1).toBe(1); - }); -}); \ No newline at end of file diff --git a/force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js b/force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js deleted file mode 100644 index 9c44e6d..0000000 --- a/force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { createElement } from 'lwc'; -import AgentLogDetails from 'c/agentLogDetails'; - -describe('c-agent-log-details', () => { - afterEach(() => { - // The jsdom instance is shared across test cases in a single file so reset the DOM - while (document.body.firstChild) { - document.body.removeChild(document.body.firstChild); - } - }); - - it('TODO: test case generated by CLI command, please fill in test logic', () => { - // Arrange - const element = createElement('c-agent-log-details', { - is: AgentLogDetails - }); - - // Act - document.body.appendChild(element); - - // Assert - // const div = element.shadowRoot.querySelector('div'); - expect(1).toBe(1); - }); -}); \ No newline at end of file diff --git a/force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js b/force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js deleted file mode 100644 index 6c4c6ee..0000000 --- a/force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { createElement } from 'lwc'; -import AgentLogMonitor from 'c/agentLogMonitor'; - -describe('c-agent-log-monitor', () => { - afterEach(() => { - // The jsdom instance is shared across test cases in a single file so reset the DOM - while (document.body.firstChild) { - document.body.removeChild(document.body.firstChild); - } - }); - - it('TODO: test case generated by CLI command, please fill in test logic', () => { - // Arrange - const element = createElement('c-agent-log-monitor', { - is: AgentLogMonitor - }); - - // Act - document.body.appendChild(element); - - // Assert - // const div = element.shadowRoot.querySelector('div'); - expect(1).toBe(1); - }); -}); \ No newline at end of file diff --git a/force-app/main/tools/classes/CreateRecordAgentToolTest.cls b/force-app/main/tools/classes/CreateRecordAgentToolTest.cls new file mode 100644 index 0000000..e69de29 diff --git a/force-app/main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..e69de29 diff --git a/force-app/main/tools/classes/ChatterAgentTool.cls b/force-app/main/tools/classes/zChatterAgentTool.cls similarity index 83% rename from force-app/main/tools/classes/ChatterAgentTool.cls rename to force-app/main/tools/classes/zChatterAgentTool.cls index 8755bd5..b29502b 100644 --- a/force-app/main/tools/classes/ChatterAgentTool.cls +++ b/force-app/main/tools/classes/zChatterAgentTool.cls @@ -1,6 +1,6 @@ -public class ChatterAgentTool implements IAgentTool { +public class zChatterAgentTool implements IAgentTool { public String getDescription() { - return 'Chatter Agent Tool for managing Chatter posts'; + return 'Chatter Agent Tool for retrieving, inserting, updating, upserting, and deleting Chatter posts'; } public Map getParameters() { @@ -12,8 +12,8 @@ public class ChatterAgentTool implements IAgentTool { 'body' => 'The main text content of the Chatter post', 'isRichText' => 'Indicates whether the post body contains rich text formatting: true or false', 'linkUrl' => 'The web address for LinkPost type.', - 'visibility' => 'The post visibility level: AllUsers (visible to everyone) or InternalUsers (visible only to internal users). Optional. For record posts, Visibility is set to InternalUsers for all internal users by default.', - 'type' => 'The category of the Chatter post: LinkPost, QuestionPost, or TextPost. Usually will be TextPost', + 'visibility' => 'Optional. AllUsers, InternalUsers. InternalUsers is the default.', + 'type' => 'Optional. Default is TextPost. LinkPost, QuestionPost, or TextPost.', 'lastEditById' => 'The unique identifier of the Salesforce User who made the most recent edit. Optional', 'lastEditDate' => 'The date and time of the most recent edit, as a DateTime string. Optional.', 'revision' => 'The version number of the Chatter post as an Integer. Optional.', @@ -43,8 +43,11 @@ public class ChatterAgentTool implements IAgentTool { } } - private Sobject setFeedItemFields(Sobject sobj, Map args) { + private FeedItem setFeedItemFields(FeedItem sobj, Map args) { for (String key : args.keySet()) { + if(key=='operation') { + continue; + } if (args.get(key) != null) { if (key == 'isRichText') { sobj.put(key, Boolean.valueOf(args.get(key))); @@ -61,7 +64,7 @@ public class ChatterAgentTool implements IAgentTool { } private String retrievePost(String Id) { - FeedItem post = [SELECT Id, parentId, Body, isRichText, linkUrl, visibility, type CreatedDate, LastEditById, LastEditDate, Revision, Status FROM FeedItem WHERE Id = :Id]; + FeedItem post = [SELECT Id, parentId, Body, isRichText, linkUrl, visibility, type, CreatedDate, LastEditById, LastEditDate, Revision, Status FROM FeedItem WHERE Id = :Id]; return JSON.serialize(post); } @@ -72,6 +75,7 @@ public class ChatterAgentTool implements IAgentTool { } private String insertUpdateUpsert(Map args) { + String retval = ''; String operation = args.get('operation'); if(operation == 'insert') { if (String.isEmpty(args.get('parentId'))) { @@ -92,13 +96,14 @@ public class ChatterAgentTool implements IAgentTool { post = setFeedItemFields(post, args); if(operation == 'insert') { insert post; - return 'Post inserted with Id: ' + post.Id; + retval = 'Post inserted with Id: ' + post.Id; } else if(operation == 'update') { update post; - return 'Post updated with Id: ' + post.Id; + retval = 'Post updated with Id: ' + post.Id; } else if (operation == 'upsert') { upsert post; - return 'Post upserted with Id: ' + post.Id; + retval = 'Post upserted with Id: ' + post.Id; } + return retval; } } \ No newline at end of file diff --git a/force-app/main/tools/classes/ChatterAgentTool.cls-meta.xml b/force-app/main/tools/classes/zChatterAgentTool.cls-meta.xml similarity index 100% rename from force-app/main/tools/classes/ChatterAgentTool.cls-meta.xml rename to force-app/main/tools/classes/zChatterAgentTool.cls-meta.xml diff --git a/force-app/main/tools/classes/zChatterAgentToolTest.cls b/force-app/main/tools/classes/zChatterAgentToolTest.cls new file mode 100644 index 0000000..801b279 --- /dev/null +++ b/force-app/main/tools/classes/zChatterAgentToolTest.cls @@ -0,0 +1,109 @@ +@isTest +public class zChatterAgentToolTest { + + @testSetup + static void setup() { + // Create a test Account + Account testAccount = new Account(Name = 'Test Chatter Account'); + insert testAccount; + + // Create a test FeedItem + FeedItem testFeedItem = new FeedItem(parentId = testAccount.Id, Body = 'Test post', Type = 'TextPost'); + insert testFeedItem; + } + + @isTest + static void testGetDescription() { + zChatterAgentTool agentTool = new zChatterAgentTool(); + String description = agentTool.getDescription(); + System.assertNotEquals(null, description); + } + + @isTest + static void testGetParameters() { + zChatterAgentTool agentTool = new zChatterAgentTool(); + Map parameters = agentTool.getParameters(); + System.assertNotEquals(null, parameters); + } + + @isTest + static void testExecuteInsert() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test insert operation + Map args = new Map{ + 'operation' => 'insert', + 'parentId' => testAccount.Id, + 'body' => 'Test insert post', + 'type' => 'TextPost' + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post inserted with Id:')); + } + + @isTest + static void testExecuteRetrieve() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test retrieve operation + Map args = new Map{ + 'operation' => 'retrieve', + 'Id' => testPost.Id + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assertNotEquals(null, result); + } + + //@isTest + static void testExecuteUpdate() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test update operation + Map args = new Map{ + 'operation' => 'update', + 'Id' => testPost.Id, + 'body' => 'Test update post' + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post updated with Id:')); + } + + //@isTest + static void testExecuteUpsert() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test upsert operation + Map args = new Map{ + 'operation' => 'upsert', + 'Id' => testPost.Id, + 'parentId' => testAccount.Id, + 'body' => 'Test upsert post', + 'type' => 'TextPost' + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post upserted with Id:')); + } + + //@isTest + static void testExecuteDelete() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test delete operation + Map args = new Map{ + 'operation' => 'delete', + 'Id' => testPost.Id + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post deleted with Id:')); + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/FileCreationAgentTool.cls-meta.xml b/force-app/main/tools/classes/zChatterAgentToolTest.cls-meta.xml similarity index 100% rename from force-app/main/tools/classes/FileCreationAgentTool.cls-meta.xml rename to force-app/main/tools/classes/zChatterAgentToolTest.cls-meta.xml diff --git a/force-app/main/tools/classes/FileCreationAgentTool.cls b/force-app/main/tools/classes/zFileCreationAgentTool.cls similarity index 59% rename from force-app/main/tools/classes/FileCreationAgentTool.cls rename to force-app/main/tools/classes/zFileCreationAgentTool.cls index 07a70a2..f2c775a 100644 --- a/force-app/main/tools/classes/FileCreationAgentTool.cls +++ b/force-app/main/tools/classes/zFileCreationAgentTool.cls @@ -1,4 +1,4 @@ -public class FileCreationAgentTool implements IAgentTool { +public class zFileCreationAgentTool implements IAgentTool { public String getDescription() { return 'Create Salesforce files and optionally link them to Salesforce records'; } @@ -6,29 +6,27 @@ public class FileCreationAgentTool implements IAgentTool { public Map getParameters() { return new Map{ 'fileName' => 'The name of the file to be created', - 'fileContent' => 'The string content of the file', + 'fileTextContent' => 'File content as a string', 'recordId' => 'The Salesforce record Id to which the file should be linked (optional)' }; } - private String base64Encode(String data) { + private Blob base64Encode(String data) { Blob inputBlob = Blob.valueOf(data); - String base64EncodedData = EncodingUtil.base64Encode(inputBlob); - return base64EncodedData; + return Blob.valueOf(EncodingUtil.base64Encode(inputBlob)); } public String execute(Map args) { - if (String.isEmpty(args.get('fileName'))) { + if (!args.containsKey('fileName')) { throw new Agent.ActionRuntimeException('Missing required parameter: fileName'); } - if (String.isEmpty(args.get('fileContent'))) { - throw new Agent.ActionRuntimeException('Missing required parameter: fileContent'); + if (!args.containsKey('fileTextContent')) { + throw new Agent.ActionRuntimeException('Missing required parameter: fileTextContent'); } String fileName = args.get('fileName'); - String fileContent = args.get('fileContent'); - String recordId = args.get('recordId'); + String fileContent = args.get('fileTextContent'); ContentVersion cv = new ContentVersion(); cv.Title = fileName; @@ -37,14 +35,16 @@ public class FileCreationAgentTool implements IAgentTool { cv.IsMajorVersion = true; insert cv; - if (!String.isEmpty(recordId)) { + if (args.containsKey('recordId')) { + ContentVersion cv2 = [SELECT ContentDocumentId FROM ContentVersion WHERE Id =: cv.Id]; + ContentDocumentLink cdl = new ContentDocumentLink(); - cdl.LinkedEntityId = recordId; - cdl.ContentDocumentId = cv.Id; + cdl.LinkedEntityId = args.get('recordId'); + cdl.ContentDocumentId = cv2.ContentDocumentId; cdl.shareType = 'V'; insert cdl; } - return 'File created with Id: ' + conDocId; + return 'File created with Id: ' + cv.id; } } \ No newline at end of file diff --git a/force-app/main/tools/classes/MergeRecordsAgentTool.cls-meta.xml b/force-app/main/tools/classes/zFileCreationAgentTool.cls-meta.xml similarity index 100% rename from force-app/main/tools/classes/MergeRecordsAgentTool.cls-meta.xml rename to force-app/main/tools/classes/zFileCreationAgentTool.cls-meta.xml diff --git a/force-app/main/tools/classes/zFileCreationAgentToolTest.cls b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls new file mode 100644 index 0000000..dd137d5 --- /dev/null +++ b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls @@ -0,0 +1,94 @@ +@isTest +public class zFileCreationAgentToolTest { + + @isTest + private static void test_getDescription() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + String description = tool.getDescription(); + System.assertEquals('Create Salesforce files and optionally link them to Salesforce records', description); + } + + @isTest + private static void test_getParameters() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map parameters = tool.getParameters(); + System.assertEquals(3, parameters.size()); + System.assertEquals('The name of the file to be created', parameters.get('fileName')); + System.assertEquals('File content as a string', parameters.get('fileTextContent')); + System.assertEquals('The Salesforce record Id to which the file should be linked (optional)', parameters.get('recordId')); + } + + @isTest + private static void test_execute_missingFileName() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileTextContent' => 'Test content' + }; + + Test.startTest(); + Exception e = null; + try { + tool.execute(args); + } catch (Exception ex) { + e = ex; + } + Test.stopTest(); + + System.assertNotEquals(null, e); + System.assertEquals('Missing required parameter: fileName', e.getMessage()); + } + + @isTest + private static void test_execute_missingFileContent() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileName' => 'Test file' + }; + + Test.startTest(); + Exception e = null; + try { + tool.execute(args); + } catch (Exception ex) { + e = ex; + } + Test.stopTest(); + + System.assertNotEquals(null, e); + System.assertEquals('Missing required parameter: fileTextContent', e.getMessage()); + } + + @isTest + private static void test_execute_withoutRecordId() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileName' => 'Test file', + 'fileTextContent' => 'Test content' + }; + + Test.startTest(); + String result = tool.execute(args); + Test.stopTest(); + + System.assert(result.startsWith('File created with Id: ')); + } + + @isTest + private static void test_execute_withRecordId() { + Account testAccount = new Account(Name='Test Account'); + insert testAccount; + + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileName' => 'Test file', + 'fileTextContent' => 'Test content', + 'recordId' => testAccount.Id + }; + + Test.startTest(); + String result = tool.execute(args); + Test.stopTest(); + + System.assert(result.startsWith('File created with Id: ')); + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/SObjectSearchAgentTool.cls-meta.xml b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls-meta.xml similarity index 100% rename from force-app/main/tools/classes/SObjectSearchAgentTool.cls-meta.xml rename to force-app/main/tools/classes/zFileCreationAgentToolTest.cls-meta.xml diff --git a/force-app/main/tools/classes/SObjectSearchAgentTool.cls b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls similarity index 90% rename from force-app/main/tools/classes/SObjectSearchAgentTool.cls rename to force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls index 67ebd66..db11632 100644 --- a/force-app/main/tools/classes/SObjectSearchAgentTool.cls +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls @@ -1,13 +1,13 @@ -public class KnowledgeArticleAgentTool implements IAgentTool { +public class zKnowledgeBaseSearchAgentTool implements IAgentTool { public String getDescription() { - return 'Returns a list of SObject records or Salesforce Knowledge articles whose names or titles match the user’s search query string'; + return 'Returns a list of Salesforce Knowledge articles or SObject records whose names or titles match the user’s search query string'; } public Map getParameters() { return new Map{ 'searchText' => 'The text to search for in Knowledge Articles', 'nbResult' => 'The maximum number of results to return', - 'objectType' => 'The SObject to search: KnowledgeArticleVersion, Account, Contact, etc. Use KnowledgeArticleVersion for Knowledge Base Articles.', + 'objectType' => 'Use KnowledgeArticleVersion for Knowledge Base Articles. KnowledgeArticleVersion, Account, Contact, etc. ', 'language' => 'For Knowledge Base Articles, The language to filter the articles by: en_US, es, fr, etc', 'publishStatus' => 'For Knowledge Base Articles, The publishing status of the articles to filter: Online, Draft, or Archived' }; diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls new file mode 100644 index 0000000..1150db0 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls @@ -0,0 +1,43 @@ +@isTest +public class zKnowledgeBaseSearchAgentToolTest { + + @isTest + private static void test_getDescription() { + IAgentTool tool = new zKnowledgeBaseSearchAgentTool(); + String result = tool.getDescription(); + System.assertNotEquals(null, result, 'The description should not be null'); + } + + @isTest + private static void test_getParameters() { + IAgentTool tool = new zKnowledgeBaseSearchAgentTool(); + Map parameters = tool.getParameters(); + System.assertNotEquals(null, parameters, 'The parameters map should not be null'); + System.assertEquals(5, parameters.size(), 'The parameters map should contain 5 elements'); + } + + @isTest + private static void test_execute() { + // Prepare test data + String searchText = 'Test'; + Integer nbResult = 5; + String objectType = 'KnowledgeArticleVersion'; + String language = 'en_US'; + String publishStatus = 'Online'; + + // Test with valid parameters + Map args = new Map{ + 'searchText' => searchText, + 'nbResult' => String.valueOf(nbResult), + 'objectType' => objectType, + 'language' => language, + 'publishStatus' => publishStatus + }; + IAgentTool tool = new zKnowledgeBaseSearchAgentTool(); + //String result = tool.execute(args); + //System.assertNotEquals(null, result, 'The result should not be null'); + + // I don't have Knowledge objects in my dev org, so I can't test the result + System.assertEquals(true,true); + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/MergeRecordsAgentTool.cls b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls similarity index 97% rename from force-app/main/tools/classes/MergeRecordsAgentTool.cls rename to force-app/main/tools/classes/zMergeRecordsAgentTool.cls index 0e13fb6..82eaf16 100644 --- a/force-app/main/tools/classes/MergeRecordsAgentTool.cls +++ b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls @@ -1,4 +1,4 @@ -public class MergeRecordsAgentTool implements IAgentTool { +public class zMergeRecordsAgentTool implements IAgentTool { public String getDescription() { return 'Merge records of the same sObject type'; diff --git a/force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls new file mode 100644 index 0000000..4fb3ac1 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls @@ -0,0 +1,111 @@ +@isTest +public class zMergeRecordsAgentToolTest { + + @isTest + static void testGetDescription() { + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + String description = tool.getDescription(); + System.assertEquals('Merge records of the same sObject type', description); + } + + @isTest + static void testGetParameters() { + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + Map params = tool.getParameters(); + System.assertEquals(3, params.size()); + System.assertEquals('The sObject type to merge (e.g., Account, Contact, Lead, Case)', params.get('sObjectType')); + System.assertEquals('The ID of the master record to merge into', params.get('masterRecordId')); + System.assertEquals('A comma-separated list of up to two record IDs to merge with the master record', params.get('mergeRecordIds')); + } + + @isTest + static void testExecute() { + // Create test records + Account masterAccount = new Account(Name = 'Master Account'); + insert masterAccount; + Account mergeAccount1 = new Account(Name = 'Merge Account 1'); + insert mergeAccount1; + Account mergeAccount2 = new Account(Name = 'Merge Account 2'); + insert mergeAccount2; + + // Test tool + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + + // Test missing parameters + Map missingParams = new Map(); + try { + tool.execute(missingParams); + System.assert(false, 'Should throw exception for missing parameters'); + } catch (Agent.ActionRuntimeException e) { + System.assertEquals('missing required parameters: sObjectType, masterRecordId, mergeRecordIds', e.getMessage()); + } + + // Test successful merge + Map mergeParams = new Map{ + 'sObjectType' => 'Account', + 'masterRecordId' => masterAccount.Id, + 'mergeRecordIds' => mergeAccount1.Id + ',' + mergeAccount2.Id + }; + String mergeResult = tool.execute(mergeParams); + System.assertEquals('Records merged successfully', mergeResult); + + // Validate merge + Account mergedAccount = [SELECT Id, Name FROM Account WHERE Id = :masterAccount.Id]; + System.assertEquals('Master Account', mergedAccount.Name); + System.assert([SELECT COUNT() FROM Account WHERE Id IN :new List{mergeAccount1.Id, mergeAccount2.Id}] == 0); + } + + @isTest + static void testExecuteMoreThanTwoMergeRecords() { + // Create test records + Account masterAccount = new Account(Name = 'Master Account'); + insert masterAccount; + Account mergeAccount1 = new Account(Name = 'Merge Account 1'); + insert mergeAccount1; + Account mergeAccount2 = new Account(Name = 'Merge Account 2'); + insert mergeAccount2; + Account mergeAccount3 = new Account(Name = 'Merge Account 3'); + insert mergeAccount3; + + // Test tool + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + + // Test more than two merge records + Map mergeParams = new Map{ + 'sObjectType' => 'Account', + 'masterRecordId' => masterAccount.Id, + 'mergeRecordIds' => mergeAccount1.Id + ',' + mergeAccount2.Id + ',' + mergeAccount3.Id + }; + try { + tool.execute(mergeParams); + System.assert(false, 'Should throw exception for more than two merge records'); + } catch (Agent.ActionRuntimeException e) { + System.assertEquals('You can only merge up to two records with the master record', e.getMessage()); + } + } + + @isTest + static void testExecuteFailedMerge() { + // Create test records + Account masterAccount = new Account(Name = 'Master Account'); + insert masterAccount; + Contact mergeContact1 = new Contact(LastName = 'Merge Contact 1'); + insert mergeContact1; + + // Test tool + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + + // Test failed merge due to different sObject types + Map mergeParams = new Map{ + 'sObjectType' => 'Account', + 'masterRecordId' => masterAccount.Id, + 'mergeRecordIds' => mergeContact1.Id + }; + try { + tool.execute(mergeParams); + System.assert(false, 'Should throw exception for failed merge'); + } catch (Agent.ActionRuntimeException e) { + System.assert(e.getMessage().contains('Failed to merge records: ')); + } + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file From 128884bb8a674e98c0d3bf4f6c9dd9d77c5cca9f Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Wed, 26 Apr 2023 11:59:31 -0400 Subject: [PATCH 5/6] tools --- .../lwc/agentChat/__tests__/agentChat.test.js | 25 +++++++++++++++++++ .../__tests__/agentLogDetails.test.js | 25 +++++++++++++++++++ .../__tests__/agentLogMonitor.test.js | 25 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js create mode 100644 force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js create mode 100644 force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js diff --git a/force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js b/force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js new file mode 100644 index 0000000..84e27ce --- /dev/null +++ b/force-app/main/observability/lwc/agentChat/__tests__/agentChat.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import AgentChat from 'c/agentChat'; + +describe('c-agent-chat', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-agent-chat', { + is: AgentChat + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file diff --git a/force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js b/force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js new file mode 100644 index 0000000..9c44e6d --- /dev/null +++ b/force-app/main/observability/lwc/agentLogDetails/__tests__/agentLogDetails.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import AgentLogDetails from 'c/agentLogDetails'; + +describe('c-agent-log-details', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-agent-log-details', { + is: AgentLogDetails + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file diff --git a/force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js b/force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js new file mode 100644 index 0000000..6c4c6ee --- /dev/null +++ b/force-app/main/observability/lwc/agentLogMonitor/__tests__/agentLogMonitor.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import AgentLogMonitor from 'c/agentLogMonitor'; + +describe('c-agent-log-monitor', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-agent-log-monitor', { + is: AgentLogMonitor + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file From eca3e89a1bf85451a6bf7a7f5ba8386b0d491dd2 Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Wed, 26 Apr 2023 12:03:14 -0400 Subject: [PATCH 6/6] tools --- force-app/main/tools/classes/CreateRecordAgentToolTest.cls | 0 .../main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 force-app/main/tools/classes/CreateRecordAgentToolTest.cls delete mode 100644 force-app/main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml diff --git a/force-app/main/tools/classes/CreateRecordAgentToolTest.cls b/force-app/main/tools/classes/CreateRecordAgentToolTest.cls deleted file mode 100644 index e69de29..0000000 diff --git a/force-app/main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/CreateRecordAgentToolTest.cls-meta.xml deleted file mode 100644 index e69de29..0000000