Skip to content

Commit

Permalink
.Net: Update stepwise planner to accept optional chatHistory to resum…
Browse files Browse the repository at this point in the history
…e execution as needed. (#5718)

### Motivation and Context

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [ ] The code builds clean without any errors or warnings
- [ ] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄

---------

Co-authored-by: Leo Hu <lifhu@microsoft.com>
Co-authored-by: Mark Wallace <127216156+markwallace-microsoft@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 4, 2024
1 parent 04994cd commit e6b3633
Showing 1 changed file with 16 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,53 @@ public sealed class FunctionCallingStepwisePlanner
/// </summary>
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use throughout the operation.</param>
/// <param name="question">The question to answer</param>
/// <param name="chatHistoryForSteps">The chat history for the steps of the plan. If null, the planner will generate the chat history for the first step.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>Result containing the model's response message and chat history.</returns>
public Task<FunctionCallingStepwisePlannerResult> ExecuteAsync(
Kernel kernel,
string question,
ChatHistory? chatHistoryForSteps = null,
CancellationToken cancellationToken = default)
{
var logger = kernel.LoggerFactory.CreateLogger(this.GetType()) ?? NullLogger.Instance;

#pragma warning disable CS8604 // Possible null reference argument.
return PlannerInstrumentation.InvokePlanAsync(
static (FunctionCallingStepwisePlanner plan, Kernel kernel, string? question, CancellationToken cancellationToken)
=> plan.ExecuteCoreAsync(kernel, question!, cancellationToken),
this, kernel, question, logger, cancellationToken);
static (FunctionCallingStepwisePlanner plan, Kernel kernel, Tuple<string?, ChatHistory?>? input, CancellationToken cancellationToken)
=> plan.ExecuteCoreAsync(kernel, input?.Item1!, input?.Item2, cancellationToken),
this, kernel, new Tuple<string?, ChatHistory?>(question, chatHistoryForSteps), logger, cancellationToken);
#pragma warning restore CS8604 // Possible null reference argument.
}

#region private

private async Task<FunctionCallingStepwisePlannerResult> ExecuteCoreAsync(
Kernel kernel,
string question,
ChatHistory chatHistoryForSteps,
CancellationToken cancellationToken = default)
{
Verify.NotNullOrWhiteSpace(question);
Verify.NotNull(kernel);
IChatCompletionService chatCompletion = kernel.GetRequiredService<IChatCompletionService>();
ILoggerFactory loggerFactory = kernel.LoggerFactory;
ILogger logger = loggerFactory.CreateLogger(this.GetType()) ?? NullLogger.Instance;
var promptTemplateFactory = new KernelPromptTemplateFactory(loggerFactory);
var stepExecutionSettings = this._options.ExecutionSettings ?? new OpenAIPromptExecutionSettings();

// Clone the kernel so that we can add planner-specific plugins without affecting the original kernel instance
var clonedKernel = kernel.Clone();
clonedKernel.ImportPluginFromType<UserInteraction>();

// Create and invoke a kernel function to generate the initial plan
var initialPlan = await this.GeneratePlanAsync(question, clonedKernel, logger, cancellationToken).ConfigureAwait(false);
if (chatHistoryForSteps is null)
{
// Create and invoke a kernel function to generate the initial plan
var promptTemplateFactory = new KernelPromptTemplateFactory(loggerFactory);
var initialPlan = await this.GeneratePlanAsync(question, clonedKernel, logger, cancellationToken).ConfigureAwait(false);

var chatHistoryForSteps = await this.BuildChatHistoryForStepAsync(question, initialPlan, clonedKernel, promptTemplateFactory, cancellationToken).ConfigureAwait(false);
// Build chat history for the first step
chatHistoryForSteps = await this.BuildChatHistoryForStepAsync(question, initialPlan, clonedKernel, promptTemplateFactory, cancellationToken).ConfigureAwait(false);
}

for (int i = 0; i < this._options.MaxIterations; i++)
{
Expand Down

0 comments on commit e6b3633

Please sign in to comment.