diff --git a/src/dotnet/Common/Models/ResourceProviders/Prompt/MultipartPrompt.cs b/src/dotnet/Common/Models/ResourceProviders/Prompt/MultipartPrompt.cs
index 054b73a5cc..077b430fb1 100644
--- a/src/dotnet/Common/Models/ResourceProviders/Prompt/MultipartPrompt.cs
+++ b/src/dotnet/Common/Models/ResourceProviders/Prompt/MultipartPrompt.cs
@@ -20,6 +20,12 @@ public class MultipartPrompt : PromptBase
[JsonPropertyName("suffix")]
public string? Suffix { get; set; }
+ ///
+ /// Optional string token replacements for the prompt.
+ ///
+ [JsonPropertyName("token_replacements")]
+ public TokenReplacementDefinition[] TokenReplacements { get; set; } = [];
+
///
/// Set default property values.
///
diff --git a/src/dotnet/Common/Models/ResourceProviders/Prompt/TokenReplacementDefinition.cs b/src/dotnet/Common/Models/ResourceProviders/Prompt/TokenReplacementDefinition.cs
new file mode 100644
index 0000000000..41a3d4bc8c
--- /dev/null
+++ b/src/dotnet/Common/Models/ResourceProviders/Prompt/TokenReplacementDefinition.cs
@@ -0,0 +1,22 @@
+using System.Text.Json.Serialization;
+
+namespace FoundationaLLM.Common.Models.ResourceProviders.Prompt
+{
+ ///
+ /// String text token replacement definition.
+ ///
+ public class TokenReplacementDefinition
+ {
+ ///
+ /// The token to be replaced.
+ ///
+ [JsonPropertyName("token")]
+ public required string Token { get; set; }
+
+ ///
+ /// The code to compute the replacement value.
+ ///
+ [JsonPropertyName("compute_code")]
+ public required string ComputeCode { get; set; }
+ }
+}
diff --git a/src/dotnet/Orchestration/Orchestration.csproj b/src/dotnet/Orchestration/Orchestration.csproj
index 97863d6cb9..f304b20efc 100644
--- a/src/dotnet/Orchestration/Orchestration.csproj
+++ b/src/dotnet/Orchestration/Orchestration.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/dotnet/Orchestration/Orchestration/OrchestrationBuilder.cs b/src/dotnet/Orchestration/Orchestration/OrchestrationBuilder.cs
index 26e2333a0a..543fe08d31 100644
--- a/src/dotnet/Orchestration/Orchestration/OrchestrationBuilder.cs
+++ b/src/dotnet/Orchestration/Orchestration/OrchestrationBuilder.cs
@@ -16,6 +16,7 @@
using FoundationaLLM.Common.Models.ResourceProviders.Prompt;
using FoundationaLLM.Common.Models.ResourceProviders.Vectorization;
using FoundationaLLM.Orchestration.Core.Interfaces;
+using FoundationaLLM.Orchestration.Core.Services.TokenReplacement;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -204,7 +205,7 @@ await cosmosDBService.PatchOperationsItemPropertiesAsync(
resourceObjectId.ObjectId,
currentUserIdentity);
+
+ if(retrievedPrompt is MultipartPrompt multipartPrompt)
+ {
+ //check for token replacements, multipartPrompt variable has the same reference as retrievedPrompt therefore this edits the prefix/suffix in place
+ if (multipartPrompt is not null && multipartPrompt.TokenReplacements != null && multipartPrompt.TokenReplacements.Length > 0)
+ {
+ var tokenReplacementEngine = new TokenReplacementEngine(multipartPrompt.TokenReplacements.ToList());
+ multipartPrompt.Prefix = await tokenReplacementEngine.ReplaceTokensAsync(multipartPrompt.Prefix!);
+ multipartPrompt.Suffix = await tokenReplacementEngine.ReplaceTokensAsync(multipartPrompt.Suffix!);
+ }
+ }
+
explodedObjectsManager.TryAdd(
retrievedPrompt.ObjectId!,
retrievedPrompt);
diff --git a/src/dotnet/Orchestration/Services/TokenReplacement/TokenReplacementEngine.cs b/src/dotnet/Orchestration/Services/TokenReplacement/TokenReplacementEngine.cs
new file mode 100644
index 0000000000..b1c82a71ad
--- /dev/null
+++ b/src/dotnet/Orchestration/Services/TokenReplacement/TokenReplacementEngine.cs
@@ -0,0 +1,68 @@
+using System.Text.RegularExpressions;
+using FoundationaLLM.Common.Models.ResourceProviders.Prompt;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+
+namespace FoundationaLLM.Orchestration.Core.Services.TokenReplacement
+{
+ ///
+ /// Token replacement engine, responsible for replacing tokens in a string with their computed values.
+ ///
+ public class TokenReplacementEngine
+ {
+ private readonly List _tokenReplacements;
+ private readonly ScriptOptions _scriptOptions;
+
+ ///
+ /// Creates an instance of the class.
+ ///
+ ///
+ public TokenReplacementEngine(List tokenReplacements)
+ {
+ _tokenReplacements = tokenReplacements;
+
+ // Define script options, such as referencing necessary assemblies and namespaces
+ _scriptOptions = ScriptOptions.Default
+ .AddImports("System");
+ }
+
+ ///
+ /// Replaces tokens in the input string with their corresponding computed values.
+ ///
+ /// The input string containing tokens to be replaced.
+ /// A task that represents the asynchronous operation. The task result contains the string with tokens replaced.
+ public async Task ReplaceTokensAsync(string input)
+ {
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ return input;
+ }
+ string pattern = @"{{\s*(\w+)\s*}}";
+ return await Task.Run(() => Regex.Replace(input, pattern, match =>
+ {
+ string tokenName = match.Groups[1].Value;
+ var tokenReplacement = _tokenReplacements.Find(tr => tr.Token == $"{{{{{tokenName}}}}}");
+
+ if (tokenReplacement != null)
+ {
+ try
+ {
+ // Evaluate the compute code
+ var result = CSharpScript.EvaluateAsync(
+ tokenReplacement.ComputeCode,
+ _scriptOptions).Result;
+ return result;
+ }
+ catch (Exception ex)
+ {
+ // Handle errors in compute code
+ return $"[Error: {ex.Message}]";
+ }
+ }
+
+ // If token not found, return it unchanged or handle as needed
+ return match.Value;
+ }, RegexOptions.IgnoreCase));
+ }
+ }
+}