diff --git a/dotnet/src/Functions/Functions.Prompty.UnitTests/Functions.Prompty.UnitTests.csproj b/dotnet/src/Functions/Functions.Prompty.UnitTests/Functions.Prompty.UnitTests.csproj index 77e97f711e7f..d58ba5a5c5dd 100644 --- a/dotnet/src/Functions/Functions.Prompty.UnitTests/Functions.Prompty.UnitTests.csproj +++ b/dotnet/src/Functions/Functions.Prompty.UnitTests/Functions.Prompty.UnitTests.csproj @@ -39,4 +39,9 @@ + + + Always + + \ No newline at end of file diff --git a/dotnet/src/Functions/Functions.Prompty.UnitTests/PromptyTest.cs b/dotnet/src/Functions/Functions.Prompty.UnitTests/PromptyTest.cs index a019f6bbfba9..aa255fe56b06 100644 --- a/dotnet/src/Functions/Functions.Prompty.UnitTests/PromptyTest.cs +++ b/dotnet/src/Functions/Functions.Prompty.UnitTests/PromptyTest.cs @@ -357,6 +357,47 @@ public void ItCreatesInputVariablesOnlyWhenNoneAreExplicitlySet() Assert.Equal(expectedVariables, kernelFunction.Metadata.Parameters.Select(p => p.Name)); } + [Fact] + public void ItShouldCreateFunctionFromPromptYamlContainingRelativeFileReferences() + { + // Arrange + Kernel kernel = new(); + var promptyPath = Path.Combine("TestData", "relativeFileReference.prompty"); + + // Act + var kernelFunction = kernel.CreateFunctionFromPromptyFile(promptyPath); + + // Assert + Assert.NotNull(kernelFunction); + var executionSettings = kernelFunction.ExecutionSettings; + Assert.Single(executionSettings!); + Assert.True(executionSettings!.ContainsKey("default")); + var defaultExecutionSetting = executionSettings["default"]; + Assert.Equal("gpt-35-turbo", defaultExecutionSetting.ModelId); + } + + [Fact] + public void ItShouldCreateFunctionFromPromptYamlContainingRelativeFileReferencesWithFileProvider() + { + // Arrange + Kernel kernel = new(); + var currentDirectory = Directory.GetCurrentDirectory(); + var promptyPath = Path.Combine("TestData", "relativeFileReference.prompty"); + using PhysicalFileProvider fileProvider = new(currentDirectory); + + // Act + var kernelFunction = kernel.CreateFunctionFromPromptyFile(promptyPath, + fileProvider); + + // Assert + Assert.NotNull(kernelFunction); + var executionSettings = kernelFunction.ExecutionSettings; + Assert.Single(executionSettings!); + Assert.True(executionSettings!.ContainsKey("default")); + var defaultExecutionSetting = executionSettings["default"]; + Assert.Equal("gpt-35-turbo", defaultExecutionSetting.ModelId); + } + private sealed class EchoTextGenerationService : ITextGenerationService { public IReadOnlyDictionary Attributes { get; } = new Dictionary(); diff --git a/dotnet/src/Functions/Functions.Prompty.UnitTests/TestData/model.json b/dotnet/src/Functions/Functions.Prompty.UnitTests/TestData/model.json new file mode 100644 index 000000000000..03781ec6580d --- /dev/null +++ b/dotnet/src/Functions/Functions.Prompty.UnitTests/TestData/model.json @@ -0,0 +1,11 @@ +{ + "api": "chat", + "configuration": { + "type": "azure_openai", + "api_version": "2023-07-01-preview" + }, + "parameters": { + "model_id": "gpt-35-turbo" + } +} + diff --git a/dotnet/src/Functions/Functions.Prompty.UnitTests/TestData/relativeFileReference.prompty b/dotnet/src/Functions/Functions.Prompty.UnitTests/TestData/relativeFileReference.prompty new file mode 100644 index 000000000000..696ca1272d4d --- /dev/null +++ b/dotnet/src/Functions/Functions.Prompty.UnitTests/TestData/relativeFileReference.prompty @@ -0,0 +1,10 @@ +--- +name: TestRelativeFileReference +description: A test prompt for relative file references +authors: + - Test Author +model: ${file:model.json} + +--- + +# This is a test prompt for relative file references diff --git a/dotnet/src/Functions/Functions.Prompty/Extensions/PromptyKernelExtensions.cs b/dotnet/src/Functions/Functions.Prompty/Extensions/PromptyKernelExtensions.cs index 19e883cb9b60..3144b49c56bb 100644 --- a/dotnet/src/Functions/Functions.Prompty/Extensions/PromptyKernelExtensions.cs +++ b/dotnet/src/Functions/Functions.Prompty/Extensions/PromptyKernelExtensions.cs @@ -34,7 +34,7 @@ public static KernelFunction CreateFunctionFromPromptyFile( Verify.NotNullOrWhiteSpace(promptyFilePath); var promptyTemplate = File.ReadAllText(promptyFilePath); - return kernel.CreateFunctionFromPrompty(promptyTemplate, promptTemplateFactory); + return kernel.CreateFunctionFromPrompty(promptyTemplate, promptTemplateFactory, promptyFilePath); } /// @@ -46,6 +46,7 @@ public static KernelFunction CreateFunctionFromPromptyFile( /// The to use when interpreting the prompt template configuration into a . /// If null, a will be used with support for Liquid and Handlebars prompt templates. /// + /// Optional: File path to the prompty file. /// The created . /// is null. /// is null. @@ -53,12 +54,13 @@ public static KernelFunction CreateFunctionFromPromptyFile( public static KernelFunction CreateFunctionFromPrompty( this Kernel kernel, string promptyTemplate, - IPromptTemplateFactory? promptTemplateFactory = null) + IPromptTemplateFactory? promptTemplateFactory = null, + string? promptyFilePath = null) { Verify.NotNull(kernel); Verify.NotNullOrWhiteSpace(promptyTemplate); - var promptTemplateConfig = KernelFunctionPrompty.ToPromptTemplateConfig(promptyTemplate); + var promptTemplateConfig = KernelFunctionPrompty.ToPromptTemplateConfig(promptyTemplate, promptyFilePath); return KernelFunctionFactory.CreateFromPrompt( promptTemplateConfig, @@ -118,6 +120,6 @@ public static KernelFunction CreateFunctionFromPromptyFile( using StreamReader reader = new(fileInfo.CreateReadStream()); var promptyTemplate = reader.ReadToEnd(); - return kernel.CreateFunctionFromPrompty(promptyTemplate, promptTemplateFactory); + return kernel.CreateFunctionFromPrompty(promptyTemplate, promptTemplateFactory, fileInfo.PhysicalPath); } } diff --git a/dotnet/src/Functions/Functions.Prompty/KernelFunctionPrompty.cs b/dotnet/src/Functions/Functions.Prompty/KernelFunctionPrompty.cs index 8b43f523f69f..8a7e821e5ad3 100644 --- a/dotnet/src/Functions/Functions.Prompty/KernelFunctionPrompty.cs +++ b/dotnet/src/Functions/Functions.Prompty/KernelFunctionPrompty.cs @@ -45,15 +45,16 @@ public static KernelFunction FromPrompty( /// Create a from a prompty template. /// /// Prompty representation of a prompt-based . + /// Optional: File path to the prompty file. /// The created . /// is null. /// is empty or composed entirely of whitespace. - public static PromptTemplateConfig ToPromptTemplateConfig(string promptyTemplate) + public static PromptTemplateConfig ToPromptTemplateConfig(string promptyTemplate, string? promptyFilePath = null) { Verify.NotNullOrWhiteSpace(promptyTemplate); Dictionary globalConfig = []; - PromptyCore.Prompty prompty = PromptyCore.Prompty.Load(promptyTemplate, globalConfig); + PromptyCore.Prompty prompty = PromptyCore.Prompty.Load(promptyTemplate, globalConfig, promptyFilePath); var promptTemplateConfig = new PromptTemplateConfig {