Skip to content

Commit 54b936c

Browse files
.Net: Implementation for NopPromptTemplateFactory (microsoft#6630)
### 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 microsoft#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 <164392973+westey-m@users.noreply.github.com>
1 parent c075832 commit 54b936c

File tree

5 files changed

+130
-1
lines changed

5 files changed

+130
-1
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace Microsoft.SemanticKernel;
7+
8+
/// <summary>
9+
/// Implementation of <see cref="IPromptTemplate"/> that just returns the prompt template.
10+
/// </summary>
11+
internal sealed class EchoPromptTemplate : IPromptTemplate
12+
{
13+
private readonly PromptTemplateConfig _promptConfig;
14+
private readonly Task<string> _renderResult;
15+
16+
/// <summary>
17+
/// Constructor for <see cref="EchoPromptTemplate"/>.
18+
/// </summary>
19+
/// <param name="promptConfig">Prompt template configuration</param>
20+
internal EchoPromptTemplate(PromptTemplateConfig promptConfig)
21+
{
22+
Verify.NotNull(promptConfig, nameof(promptConfig));
23+
Verify.NotNull(promptConfig.Template, nameof(promptConfig.Template));
24+
25+
this._promptConfig = promptConfig;
26+
this._renderResult = Task.FromResult(this._promptConfig.Template);
27+
}
28+
29+
/// <inheritdoc/>
30+
#pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks
31+
public Task<string> RenderAsync(Kernel kernel, KernelArguments? arguments = null, CancellationToken cancellationToken = default) => this._renderResult;
32+
#pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks
33+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Diagnostics.CodeAnalysis;
4+
5+
namespace Microsoft.SemanticKernel;
6+
7+
/// <summary>
8+
/// Provides an implementation of <see cref="IPromptTemplateFactory"/> which creates no operation instances of <see cref="IPromptTemplate"/>.
9+
/// </summary>
10+
public sealed class EchoPromptTemplateFactory : IPromptTemplateFactory
11+
{
12+
/// <summary>
13+
/// Singleton instance of <see cref="EchoPromptTemplateFactory"/>.
14+
/// </summary>
15+
public static EchoPromptTemplateFactory Instance { get; } = new EchoPromptTemplateFactory();
16+
17+
/// <inheritdoc/>
18+
public bool TryCreate(PromptTemplateConfig templateConfig, [NotNullWhen(true)] out IPromptTemplate? result)
19+
{
20+
result = new EchoPromptTemplate(templateConfig);
21+
22+
return true;
23+
}
24+
}

dotnet/src/SemanticKernel.Core/PromptTemplate/KernelPromptTemplate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace Microsoft.SemanticKernel;
2727
internal sealed class KernelPromptTemplate : IPromptTemplate
2828
{
2929
/// <summary>
30-
/// Constructor for PromptTemplate.
30+
/// Constructor for <see cref="KernelPromptTemplate"/>.
3131
/// </summary>
3232
/// <param name="promptConfig">Prompt template configuration</param>
3333
/// <param name="allowDangerouslySetContent">Flag indicating whether to allow potentially dangerous content to be inserted into the prompt</param>

dotnet/src/SemanticKernel.UnitTests/Functions/KernelFunctionFromPromptTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,34 @@ public async Task ItUsesPromptAsUserMessageAsync(KernelInvocationType invocation
654654
Assert.Equal("Test prompt as user message", messageContent.Content);
655655
}
656656

657+
[Theory]
658+
[InlineData("semantic-kernel", "This is my prompt {{$input}}")]
659+
[InlineData("handlebars", "This is my prompt {{input}}")]
660+
public async Task ItUsesPromptWithEchoPromptTemplateFactoryAsync(string templateFormat, string template)
661+
{
662+
// Arrange
663+
var mockTextGeneration = new Mock<ITextGenerationService>();
664+
var fakeTextContent = new TextContent(template);
665+
666+
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]);
667+
668+
IKernelBuilder builder = Kernel.CreateBuilder();
669+
builder.Services.AddKeyedSingleton("x", mockTextGeneration.Object);
670+
Kernel kernel = builder.Build();
671+
672+
var promptConfig = new PromptTemplateConfig(template) { TemplateFormat = templateFormat };
673+
var func = kernel.CreateFunctionFromPrompt(promptConfig, promptTemplateFactory: new EchoPromptTemplateFactory());
674+
var args = new KernelArguments();
675+
args["input"] = "Some Input";
676+
677+
// Act
678+
var result = await kernel.InvokeAsync(func, args);
679+
680+
// Assert
681+
mockTextGeneration.Verify(a => a.GetTextContentsAsync(template, It.IsAny<PromptExecutionSettings>(), It.IsAny<Kernel>(), It.IsAny<CancellationToken>()), Times.Once());
682+
Assert.Equal(template, result.GetValue<string>());
683+
}
684+
657685
[Fact]
658686
public async Task InvokePromptAsyncWithTextGenerationReturnsSingleResultAsync()
659687
{
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Threading.Tasks;
4+
using Microsoft.SemanticKernel;
5+
using Xunit;
6+
7+
namespace SemanticKernel.UnitTests.PromptTemplate;
8+
9+
public sealed class EchoPromptTemplateTests
10+
{
11+
[Fact]
12+
public async Task ItDoesNothingForSemanticKernelFormatAsync()
13+
{
14+
// Arrange
15+
var template = """This {{$x11}} {{$a}}{{$missing}} test template {{p.bar $b}} and {{p.foo c='literal "c"' d = $d}} and {{p.baz ename=$e}}""";
16+
var promptTemplateConfig = new PromptTemplateConfig(template);
17+
var templateFactory = new EchoPromptTemplateFactory();
18+
19+
// Act
20+
var target = templateFactory.Create(promptTemplateConfig);
21+
var result = await target.RenderAsync(new Kernel());
22+
23+
// Assert
24+
Assert.NotNull(result);
25+
Assert.Equal(template, result);
26+
}
27+
28+
[Fact]
29+
public async Task ItDoesNothingForHandlebarsFormatAsync()
30+
{
31+
// Arrange
32+
var template = """This {{x11}} {{a}}{{missing}} test template {{p.bar b}} and {{p.foo c='literal "c"' d = d}} and {{p.baz ename=e}}""";
33+
var promptTemplateConfig = new PromptTemplateConfig(template) { TemplateFormat = "handlebars" };
34+
var templateFactory = new EchoPromptTemplateFactory();
35+
36+
// Act
37+
var target = templateFactory.Create(promptTemplateConfig);
38+
var result = await target.RenderAsync(new Kernel());
39+
40+
// Assert
41+
Assert.NotNull(result);
42+
Assert.Equal(template, result);
43+
}
44+
}

0 commit comments

Comments
 (0)