In this blog, we’ll explore how to automatically generate a case summary when a Salesforce Case status transitions to “Escalated”, using the Agentforce Models AI API.
This time, instead of posting to Chatter, we’ll directly update the Case Description field with a concise, AI-crafted summary. Using Apex Queueable jobs and OpenAI-powered prompts, we bring intelligence into your support workflow—reducing manual input and improving clarity across escalated cases.
🧠 The Idea
When a support Case is escalated, it usually means the issue is complex or urgent. That’s where a summarized context becomes essential—for managers, engineers, or whoever picks up the case next. Instead of relying on agents to rewrite details, we’ll let AI summarize it for us.
💡 Design Overview
This solution uses:
- Apex Triggers + Handler Pattern
- Queueable class to handle callouts
aiplatform.ModelsAPI.createGenerations()to create the summary- AI-generated text written back to the Case Description
⚙️ How It Works
1. Trigger Fires
The trigger is simple: it detects when a Case is inserted or updated and forwards to the CaseTriggerHandler.
trigger CaseTrigger on Case (after insert, after update) {
if (Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {
CaseTriggerHandler.handleAfterInsertOrUpdate(Trigger.new, Trigger.oldMap);
}
}2. Logic in the Handler Class
We check for a transition to the “Escalated” status, and for each such case, we enqueue the AI summary generator.
public class CaseTriggerHandler {
public static void handleAfterInsertOrUpdate(List<Case> newCases, Map<Id, Case> oldMap) {
if (newCases == null || newCases.isEmpty()) {
return;
}
List<Id> toSummarize = new List<Id>();
for (Case newCase : newCases) {
if (newCase == null || String.isBlank(newCase.Status)) {
continue;
}
Case oldCase = oldMap != null ? oldMap.get(newCase.Id) : null;
String oldStatus = oldCase != null ? oldCase.Status : null;
// Check for transition to 'Escalated'
if (oldStatus != 'Escalated' && newCase.Status == 'Escalated') {
toSummarize.add(newCase.Id);
}
}
for (Id caseId : toSummarize) {
System.enqueueJob(new GenerateCaseSummaryQueueable(caseId));
}
}
}3. AI Generates and Updates the Summary
The GenerateCaseSummaryQueueable class does the heavy lifting: fetches Case data, builds a prompt, sends it to Agentforce AI, and writes the result to the Description field.
public class GenerateCaseSummaryQueueable implements Queueable, Database.AllowsCallouts {
private static final String MODEL_NAME = 'sfdc_ai__DefaultOpenAIGPT4OmniMini';
private static final String PROMPT_PREFIX = 'Generate a summary of a customer support case based on the following details: ';
private static final String PROMPT_SUFFIX = '. This case has just been created or updated.';
private final Id caseId;
public GenerateCaseSummaryQueueable(Id caseId) {
this.caseId = caseId;
}
public void execute(QueueableContext context) {
if (caseId == null) {
return;
}
try {
Case caseRecord = [
SELECT Id, Subject, Status, Priority, Description
FROM Case
WHERE Id = :caseId
LIMIT 1
];
String caseDetails = String.format(
'Subject: {0}, Status: {1}, Priority: {2}, Description: {3}',
new List<String>{
String.valueOf(caseRecord.Subject),
String.valueOf(caseRecord.Status),
String.valueOf(caseRecord.Priority),
String.valueOf(caseRecord.Description)
}
);
String prompt = PROMPT_PREFIX + caseDetails + PROMPT_SUFFIX;
aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
aiplatform.ModelsAPI.createGenerations_Request request = new aiplatform.ModelsAPI.createGenerations_Request();
request.modelName = MODEL_NAME;
aiplatform.ModelsAPI_GenerationRequest requestBody = new aiplatform.ModelsAPI_GenerationRequest();
requestBody.prompt = prompt;
request.body = requestBody;
aiplatform.ModelsAPI.createGenerations_Response response = modelsAPI.createGenerations(request);
String summaryText = (response != null && response.Code200 != null)
? response.Code200.generation.generatedText
: null;
if (String.isNotBlank(summaryText)) {
caseRecord.Description = summaryText;
try {
update caseRecord;
} catch (DmlException dmlEx) {
System.debug(LoggingLevel.ERROR, 'DML error while updating Case: ' + caseId + ' => ' + dmlEx.getMessage());
}
}
} catch (QueryException qEx) {
System.debug(LoggingLevel.ERROR, 'Query failed for Case Id: ' + caseId + ' => ' + qEx.getMessage());
} catch (aiplatform.ModelsAPI.createGenerations_ResponseException aiEx) {
System.debug(LoggingLevel.ERROR, 'AI API error for Case Id: ' + caseId + ' => ' + aiEx.getMessage());
} catch (Exception ex) {
System.debug(LoggingLevel.ERROR, 'Unexpected error for Case Id: ' + caseId + ' => ' + ex.getMessage());
}
}
}✅ Key Benefits
- Contextual Summaries: No more vague or incomplete descriptions. Let AI summarize what matters most.
- Trigger-Based: Kicks in only on escalation—no unnecessary API calls.
- Queueable & Callout Ready: Avoids hitting limits by processing asynchronously.
- Fully Native: Uses Salesforce-hosted Gen AI—no external APIs or integration headaches.
⚠️ Gotchas and Best Practices
- Queueable vs Future: Queueable allows better chaining and is more scalable than
@future. - Callout Limits: Still subject to daily org-wide callout limits—monitor in production.
- Avoid Overwrites: Be cautious if the
Descriptionfield is used by agents; consider using a customSummary__cfield. - Prompt Engineering: Small changes in prompt design can drastically change AI output quality.
🔚 Final Thoughts
With the Agentforce Models AI API, summarizing complex support cases becomes a seamless, intelligent, and automated process. This workflow not only reduces manual effort but enhances clarity and collaboration across support teams.
Imagine this applied not just to escalation—but to case closures, status updates, or even internal handoffs. The possibilities with AI in Apex are just beginning.
Demo : Agentforce Models AI API: Generating Case Summaries with Apex Queueable

Do you need help?
Are you stuck while working on this requirement? Do you want to get review of your solution? Now, you can book dedicated 1:1 with me on Lightning Web Component and Agentforce completely free.
GET IN TOUCH
