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
{