Enable more analyzers and various code tweaks/cleanup (#738)

This commit is contained in:
Stephen Toub
2025-09-17 21:48:25 -04:00
committed by GitHub
Unverified
parent f3264966ff
commit 5e5761b288
326 changed files with 2402 additions and 3642 deletions
@@ -53,11 +53,11 @@ public static class Program
var handleSpamExecutor = new HandleSpamExecutor();
// Build the workflow by adding executors and connecting them
WorkflowBuilder builder = new(spamDetectionExecutor);
builder.AddEdge(spamDetectionExecutor, emailAssistantExecutor, condition: GetCondition(expectedResult: false));
builder.AddEdge(emailAssistantExecutor, sendEmailExecutor);
builder.AddEdge(spamDetectionExecutor, handleSpamExecutor, condition: GetCondition(expectedResult: true));
var workflow = builder.Build<ChatMessage>();
var workflow = new WorkflowBuilder(spamDetectionExecutor)
.AddEdge(spamDetectionExecutor, emailAssistantExecutor, condition: GetCondition(expectedResult: false))
.AddEdge(emailAssistantExecutor, sendEmailExecutor)
.AddEdge(spamDetectionExecutor, handleSpamExecutor, condition: GetCondition(expectedResult: true))
.Build<ChatMessage>();
// Read a email from a text file
string email = Resources.Read("spam.txt");
@@ -79,53 +79,34 @@ public static class Program
/// </summary>
/// <param name="expectedResult">The expected spam detection result</param>
/// <returns>A function that evaluates whether a message meets the expected result</returns>
private static Func<object?, bool> GetCondition(bool expectedResult)
{
return detectionResult =>
{
return detectionResult is DetectionResult result && result.IsSpam == expectedResult;
};
}
private static Func<object?, bool> GetCondition(bool expectedResult) =>
detectionResult => detectionResult is DetectionResult result && result.IsSpam == expectedResult;
/// <summary>
/// Creates a spam detection agent.
/// </summary>
/// <returns>A ChatClientAgent configured for spam detection</returns>
private static ChatClientAgent GetSpamDetectionAgent(IChatClient chatClient)
{
string instructions = "You are a spam detection assistant that identifies spam emails.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetSpamDetectionAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are a spam detection assistant that identifies spam emails.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(DetectionResult))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(DetectionResult)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
/// <summary>
/// Creates an email assistant agent.
/// </summary>
/// <returns>A ChatClientAgent configured for email assistance</returns>
private static ChatClientAgent GetEmailAssistantAgent(IChatClient chatClient)
{
string instructions = "You are an email assistant that helps users draft responses to emails with professionalism.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetEmailAssistantAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are an email assistant that helps users draft responses to emails with professionalism.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(EmailResponse))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(EmailResponse)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
}
/// <summary>
@@ -188,7 +169,7 @@ internal sealed class SpamDetectionExecutor : ReflectingExecutor<SpamDetectionEx
EmailId = Guid.NewGuid().ToString(),
EmailContent = message.Text
};
await context.QueueStateUpdateAsync<Email>(newEmail.EmailId, newEmail, scopeName: EmailStateConstants.EmailStateScope);
await context.QueueStateUpdateAsync(newEmail.EmailId, newEmail, scopeName: EmailStateConstants.EmailStateScope);
// Invoke the agent
var response = await this._spamDetectionAgent.RunAsync(message);
@@ -252,10 +233,8 @@ internal sealed class SendEmailExecutor() : ReflectingExecutor<SendEmailExecutor
/// <summary>
/// Simulate the sending of an email.
/// </summary>
public async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context)
{
public async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context) =>
await context.AddEventAsync(new WorkflowCompletedEvent($"Email sent: {message.Response}"));
}
}
/// <summary>
@@ -94,53 +94,33 @@ public static class Program
/// </summary>
/// <param name="expectedDecision">The expected spam detection decision</param>
/// <returns>A function that evaluates whether a message meets the expected result</returns>
private static Func<object?, bool> GetCondition(SpamDecision expectedDecision)
{
return detectionResult =>
{
return detectionResult is DetectionResult result && result.spamDecision == expectedDecision;
};
}
private static Func<object?, bool> GetCondition(SpamDecision expectedDecision) => detectionResult => detectionResult is DetectionResult result && result.spamDecision == expectedDecision;
/// <summary>
/// Creates a spam detection agent.
/// </summary>
/// <returns>A ChatClientAgent configured for spam detection</returns>
private static ChatClientAgent GetSpamDetectionAgent(IChatClient chatClient)
{
string instructions = "You are a spam detection assistant that identifies spam emails. Be less confident in your assessments.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetSpamDetectionAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are a spam detection assistant that identifies spam emails. Be less confident in your assessments.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(DetectionResult))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(DetectionResult)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
/// <summary>
/// Creates an email assistant agent.
/// </summary>
/// <returns>A ChatClientAgent configured for email assistance</returns>
private static ChatClientAgent GetEmailAssistantAgent(IChatClient chatClient)
{
string instructions = "You are an email assistant that helps users draft responses to emails with professionalism.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetEmailAssistantAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are an email assistant that helps users draft responses to emails with professionalism.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(EmailResponse))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(EmailResponse)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
}
/// <summary>
@@ -213,7 +193,7 @@ internal sealed class SpamDetectionExecutor : ReflectingExecutor<SpamDetectionEx
EmailId = Guid.NewGuid().ToString(),
EmailContent = message.Text
};
await context.QueueStateUpdateAsync<Email>(newEmail.EmailId, newEmail, scopeName: EmailStateConstants.EmailStateScope);
await context.QueueStateUpdateAsync(newEmail.EmailId, newEmail, scopeName: EmailStateConstants.EmailStateScope);
// Invoke the agent
var response = await this._spamDetectionAgent.RunAsync(message);
@@ -276,10 +256,8 @@ internal sealed class SendEmailExecutor() : ReflectingExecutor<SendEmailExecutor
/// <summary>
/// Simulate the sending of an email.
/// </summary>
public async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context)
{
public async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context) =>
await context.AddEventAsync(new WorkflowCompletedEvent($"Email sent: {message.Response}"));
}
}
/// <summary>
@@ -78,7 +78,7 @@ public static class Program
.AddEdge<AnalysisResult>(
emailAnalysisExecutor,
databaseAccessExecutor,
condition: analysisResult => analysisResult is not null && analysisResult.EmailLength <= LongEmailThreshold)
condition: analysisResult => analysisResult?.EmailLength <= LongEmailThreshold)
// Save the analysis result to the database with summary
.AddEdge(emailSummaryExecutor, databaseAccessExecutor);
var workflow = builder.Build<ChatMessage>();
@@ -141,61 +141,40 @@ public static class Program
/// Create an email analysis agent.
/// </summary>
/// <returns>A ChatClientAgent configured for email analysis</returns>
private static ChatClientAgent GetEmailAnalysisAgent(IChatClient chatClient)
{
string instructions = "You are a spam detection assistant that identifies spam emails.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetEmailAnalysisAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are a spam detection assistant that identifies spam emails.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(AnalysisResult))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(AnalysisResult)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
/// <summary>
/// Creates an email assistant agent.
/// </summary>
/// <returns>A ChatClientAgent configured for email assistance</returns>
private static ChatClientAgent GetEmailAssistantAgent(IChatClient chatClient)
{
string instructions = "You are an email assistant that helps users draft responses to emails with professionalism.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetEmailAssistantAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are an email assistant that helps users draft responses to emails with professionalism.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(EmailResponse))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(EmailResponse)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
/// <summary>
/// Creates an agent that summarizes emails.
/// </summary>
/// <returns>A ChatClientAgent configured for email summarization</returns>
private static ChatClientAgent GetEmailSummaryAgent(IChatClient chatClient)
{
string instructions = "You are an assistant that helps users summarize emails.";
var agentOptions = new ChatClientAgentOptions(instructions: instructions)
private static ChatClientAgent GetEmailSummaryAgent(IChatClient chatClient) =>
new(chatClient, new ChatClientAgentOptions(instructions: "You are an assistant that helps users summarize emails.")
{
ChatOptions = new()
{
ResponseFormat = ChatResponseFormatJson.ForJsonSchema(
schema: AIJsonUtilities.CreateJsonSchema(typeof(EmailSummary))
)
ResponseFormat = ChatResponseFormat.ForJsonSchema(AIJsonUtilities.CreateJsonSchema(typeof(EmailSummary)))
}
};
return new ChatClientAgent(chatClient, agentOptions);
}
});
}
internal static class EmailStateConstants
@@ -271,7 +250,7 @@ internal sealed class EmailAnalysisExecutor : ReflectingExecutor<EmailAnalysisEx
EmailId = Guid.NewGuid().ToString(),
EmailContent = message.Text
};
await context.QueueStateUpdateAsync<Email>(newEmail.EmailId, newEmail, scopeName: EmailStateConstants.EmailStateScope);
await context.QueueStateUpdateAsync(newEmail.EmailId, newEmail, scopeName: EmailStateConstants.EmailStateScope);
// Invoke the agent
var response = await this._emailAnalysisAgent.RunAsync(message);
@@ -335,10 +314,8 @@ internal sealed class SendEmailExecutor() : ReflectingExecutor<SendEmailExecutor
/// <summary>
/// Simulate the sending of an email.
/// </summary>
public async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context)
{
public async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context) =>
await context.AddEventAsync(new WorkflowCompletedEvent($"Email sent: {message.Response}"));
}
}
/// <summary>
@@ -437,7 +414,7 @@ internal sealed class DatabaseAccessExecutor() : ReflectingExecutor<DatabaseAcce
public async ValueTask HandleAsync(AnalysisResult message, IWorkflowContext context)
{
// 1. Save the email content
var email = await context.ReadStateAsync<Email>(message.EmailId, scopeName: EmailStateConstants.EmailStateScope);
await context.ReadStateAsync<Email>(message.EmailId, scopeName: EmailStateConstants.EmailStateScope);
await Task.Delay(100); // Simulate database access delay
// 2. Save the analysis result