Skip to content

Commit

Permalink
.Net: Implementation for NopPromptTemplateFactory (#6630)
Browse files Browse the repository at this point in the history
### 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

Closes #6575 

### 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: westey <[email protected]>
  • Loading branch information
markwallace-microsoft and westey-m committed Jun 19, 2024
1 parent c075832 commit 54b936c
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.SemanticKernel;

/// <summary>
/// Implementation of <see cref="IPromptTemplate"/> that just returns the prompt template.
/// </summary>
internal sealed class EchoPromptTemplate : IPromptTemplate
{
private readonly PromptTemplateConfig _promptConfig;
private readonly Task<string> _renderResult;

/// <summary>
/// Constructor for <see cref="EchoPromptTemplate"/>.
/// </summary>
/// <param name="promptConfig">Prompt template configuration</param>
internal EchoPromptTemplate(PromptTemplateConfig promptConfig)
{
Verify.NotNull(promptConfig, nameof(promptConfig));
Verify.NotNull(promptConfig.Template, nameof(promptConfig.Template));

this._promptConfig = promptConfig;
this._renderResult = Task.FromResult(this._promptConfig.Template);
}

/// <inheritdoc/>
#pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks
public Task<string> RenderAsync(Kernel kernel, KernelArguments? arguments = null, CancellationToken cancellationToken = default) => this._renderResult;
#pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.SemanticKernel;

/// <summary>
/// Provides an implementation of <see cref="IPromptTemplateFactory"/> which creates no operation instances of <see cref="IPromptTemplate"/>.
/// </summary>
public sealed class EchoPromptTemplateFactory : IPromptTemplateFactory
{
/// <summary>
/// Singleton instance of <see cref="EchoPromptTemplateFactory"/>.
/// </summary>
public static EchoPromptTemplateFactory Instance { get; } = new EchoPromptTemplateFactory();

/// <inheritdoc/>
public bool TryCreate(PromptTemplateConfig templateConfig, [NotNullWhen(true)] out IPromptTemplate? result)
{
result = new EchoPromptTemplate(templateConfig);

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace Microsoft.SemanticKernel;
internal sealed class KernelPromptTemplate : IPromptTemplate
{
/// <summary>
/// Constructor for PromptTemplate.
/// Constructor for <see cref="KernelPromptTemplate"/>.
/// </summary>
/// <param name="promptConfig">Prompt template configuration</param>
/// <param name="allowDangerouslySetContent">Flag indicating whether to allow potentially dangerous content to be inserted into the prompt</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,34 @@ public async Task ItUsesPromptAsUserMessageAsync(KernelInvocationType invocation
Assert.Equal("Test prompt as user message", messageContent.Content);
}

[Theory]
[InlineData("semantic-kernel", "This is my prompt {{$input}}")]
[InlineData("handlebars", "This is my prompt {{input}}")]
public async Task ItUsesPromptWithEchoPromptTemplateFactoryAsync(string templateFormat, string template)
{
// Arrange
var mockTextGeneration = new Mock<ITextGenerationService>();
var fakeTextContent = new TextContent(template);

mockTextGeneration.Setup(c => c.GetTextContentsAsync(It.Is<string>(p => p.Equals(template, StringComparison.Ordinal)), It.IsAny<PromptExecutionSettings>(), It.IsAny<Kernel>(), It.IsAny<CancellationToken>())).ReturnsAsync([fakeTextContent]);

IKernelBuilder builder = Kernel.CreateBuilder();
builder.Services.AddKeyedSingleton("x", mockTextGeneration.Object);
Kernel kernel = builder.Build();

var promptConfig = new PromptTemplateConfig(template) { TemplateFormat = templateFormat };
var func = kernel.CreateFunctionFromPrompt(promptConfig, promptTemplateFactory: new EchoPromptTemplateFactory());
var args = new KernelArguments();
args["input"] = "Some Input";

// Act
var result = await kernel.InvokeAsync(func, args);

// Assert
mockTextGeneration.Verify(a => a.GetTextContentsAsync(template, It.IsAny<PromptExecutionSettings>(), It.IsAny<Kernel>(), It.IsAny<CancellationToken>()), Times.Once());
Assert.Equal(template, result.GetValue<string>());
}

[Fact]
public async Task InvokePromptAsyncWithTextGenerationReturnsSingleResultAsync()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Xunit;

namespace SemanticKernel.UnitTests.PromptTemplate;

public sealed class EchoPromptTemplateTests
{
[Fact]
public async Task ItDoesNothingForSemanticKernelFormatAsync()
{
// Arrange
var template = """This {{$x11}} {{$a}}{{$missing}} test template {{p.bar $b}} and {{p.foo c='literal "c"' d = $d}} and {{p.baz ename=$e}}""";
var promptTemplateConfig = new PromptTemplateConfig(template);
var templateFactory = new EchoPromptTemplateFactory();

// Act
var target = templateFactory.Create(promptTemplateConfig);
var result = await target.RenderAsync(new Kernel());

// Assert
Assert.NotNull(result);
Assert.Equal(template, result);
}

[Fact]
public async Task ItDoesNothingForHandlebarsFormatAsync()
{
// Arrange
var template = """This {{x11}} {{a}}{{missing}} test template {{p.bar b}} and {{p.foo c='literal "c"' d = d}} and {{p.baz ename=e}}""";
var promptTemplateConfig = new PromptTemplateConfig(template) { TemplateFormat = "handlebars" };
var templateFactory = new EchoPromptTemplateFactory();

// Act
var target = templateFactory.Create(promptTemplateConfig);
var result = await target.RenderAsync(new Kernel());

// Assert
Assert.NotNull(result);
Assert.Equal(template, result);
}
}

0 comments on commit 54b936c

Please sign in to comment.