.NET: [BREAKING] Remove Support for Code-Gen in Declarative Workflows (#6095)

* Removed

* Remove sample

* Remove orphaned code-gen related code path

* Remove remaining references to code gen.

---------

Co-authored-by: Chris Rickman <crickman@microsoft.com>
Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
This commit is contained in:
Peter Ibekwe
2026-05-27 13:14:38 -07:00
committed by GitHub
Unverified
parent 4c4e1d9b87
commit 5d8dd4ea4b
120 changed files with 4 additions and 8443 deletions
@@ -1,27 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal abstract class ActionTemplate : CodeTemplate, IModeledAction
{
public string Id { get; private set; } = string.Empty;
public string Name { get; private set; } = string.Empty;
public string ParentId { get; private set; } = string.Empty;
public bool UseAgentProvider { get; init; }
protected TAction Initialize<TAction>(TAction model) where TAction : DialogAction
{
this.Id = model.GetId();
this.ParentId = model.GetParentId() ?? WorkflowActionVisitor.Steps.Root();
this.Name = this.Id.FormatType();
return model;
}
}
@@ -1,395 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class AddConversationMessageTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Adds a new message to the specified agent conversation\n/// </s" +
"ummary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExe" +
"cutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
EvaluateStringExpression(this.Model.ConversationId, "conversationId", isNullable: true);
this.Write("\n if (string.IsNullOrWhiteSpace(conversationId))\n {\n thr" +
"ow new DeclarativeActionException($\"Conversation identifier must be defined: {th" +
"is.Id}\");\n }\n ChatMessage newMessage = new(ChatRole.");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatEnum(this.Model.Role, RoleMap)));
this.Write(", await this.GetContentAsync(context).ConfigureAwait(false)) { AdditionalProperti" +
"es = this.GetMetadata() };\n newMessage = await agentProvider.CreateMessag" +
"eAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);");
AssignVariable(this.Message, "newMessage");
this.Write("\n return default;\n }\n\n private async ValueTask<IList<AIContent>> Get" +
"ContentAsync(IWorkflowContext context)\n {\n List<AIContent> content = [" +
"];\n ");
int index = 0;
foreach (AddConversationMessageContent content in this.Model.Content)
{
++index;
EvaluateMessageTemplate(content.Value, $"contentValue{index}");
AgentMessageContentType contentType = content.Type.Value;
if (contentType == AgentMessageContentType.ImageUrl)
{
this.Write("\n content.Add(UriContent(contentValue");
this.Write(this.ToStringHelper.ToStringWithCulture(index));
this.Write(", \"image/*\"));");
}
else if (contentType == AgentMessageContentType.ImageFile)
{
this.Write("\n content.Add(new HostedFileContent(contentValue");
this.Write(this.ToStringHelper.ToStringWithCulture(index));
this.Write("));");
}
else
{
this.Write("\n content.Add(new TextContent(contentValue");
this.Write(this.ToStringHelper.ToStringWithCulture(index));
this.Write("));");
}
}
this.Write("\n return content;\n }\n\n private AdditionalPropertiesDictionary? GetMe" +
"tadata()\n {");
EvaluateRecordExpression<object>(this.Model.Metadata, "metadata");
this.Write("\n\n if (metadata is null)\n {\n return null; \n }\n" +
"\n return new AdditionalPropertiesDictionary(metadata);\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateRecordExpression<TValue>(ObjectExpression<RecordDataValue> expression, string targetVariable)
{
string resultTypeName = $"Dictionary<string, {GetTypeAlias<TValue>()}?>?";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" =\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateExpressionAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateExpressionAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateStringExpression(StringExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "string?" : "string";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(isNullable ? "null" : "string.Empty"));
this.Write(";");
}
else if (expression.IsLiteral)
{
if (expression.LiteralValue.Contains("\n"))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = \n \"\"\"\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.LiteralValue));
this.Write("\n \"\"\";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.LiteralValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<string>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateMessageTemplate(TemplateLine templateLine, string variableName)
{
if (templateLine is not null)
{
this.Write("\n string ");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write(" =\n await context.FormatTemplateAsync(\n \"\"\"");
FormatMessageTemplate(templateLine);
this.Write("\n \"\"\");");
}
else
{
this.Write("\n string? ");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write(" = null;");
}
}
void FormatMessageTemplate(TemplateLine line)
{
foreach (string text in line.ToTemplateString().ByLine())
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(text));
}
}
}
}
@@ -1,67 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateRecordExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateStringExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/FormatMessageTemplate.tt" once="true" #>
/// <summary>
/// Adds a new message to the specified agent conversation
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateStringExpression(this.Model.ConversationId, "conversationId", isNullable: true); #>
if (string.IsNullOrWhiteSpace(conversationId))
{
throw new DeclarativeActionException($"Conversation identifier must be defined: {this.Id}");
}
ChatMessage newMessage = new(ChatRole.<#= FormatEnum(this.Model.Role, RoleMap) #>, await this.GetContentAsync(context).ConfigureAwait(false)) { AdditionalProperties = this.GetMetadata() };
newMessage = await agentProvider.CreateMessageAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);<#
AssignVariable(this.Message, "newMessage");
#>
return default;
}
private async ValueTask<IList<AIContent>> GetContentAsync(IWorkflowContext context)
{
List<AIContent> content = [];
<#
int index = 0;
foreach (AddConversationMessageContent content in this.Model.Content)
{
++index;
EvaluateMessageTemplate(content.Value, $"contentValue{index}");
AgentMessageContentType contentType = content.Type.Value;
if (contentType == AgentMessageContentType.ImageUrl)
{#>
content.Add(UriContent(contentValue<#= index #>, "image/*"));<#
}
else if (contentType == AgentMessageContentType.ImageFile)
{#>
content.Add(new HostedFileContent(contentValue<#= index #>));<#
}
else
{#>
content.Add(new TextContent(contentValue<#= index #>));<#
}
}#>
return content;
}
private AdditionalPropertiesDictionary? GetMetadata()
{<#
EvaluateRecordExpression<object>(this.Model.Metadata, "metadata"); #>
if (metadata is null)
{
return null;
}
return new AdditionalPropertiesDictionary(metadata);
}
}
@@ -1,31 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Frozen;
using System.Collections.Generic;
using Microsoft.Agents.ObjectModel;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class AddConversationMessageTemplate
{
public AddConversationMessageTemplate(AddConversationMessage model)
{
this.Model = this.Initialize(model);
this.Message = this.Model.Message?.Path;
this.UseAgentProvider = true;
}
public AddConversationMessage Model { get; }
public PropertyPath? Message { get; }
public const string DefaultRole = nameof(ChatRole.User);
public static readonly FrozenDictionary<AgentMessageRoleWrapper, string> RoleMap =
new Dictionary<AgentMessageRoleWrapper, string>()
{
[AgentMessageRoleWrapper.Get(AgentMessageRole.User)] = nameof(ChatRole.User),
[AgentMessageRoleWrapper.Get(AgentMessageRole.Agent)] = nameof(ChatRole.Assistant),
}.ToFrozenDictionary();
}
@@ -1,221 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System.Collections.Generic;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class ClearAllVariablesTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Reset all the state for the targeted variable scope.\n/// </sum" +
"mary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
EvaluateEnumExpression<VariablesToClearWrapper, string>(this.Model.Variables, "targetScopeName", ScopeMap, isNullable: true);
this.Write("\n await context.QueueClearScopeAsync(targetScopeName).ConfigureAwait(false" +
");\n\n return default;\n }\n}\n");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateEnumExpression<TWrapper, TValue>(
EnumExpression<TWrapper> expression,
string targetVariable,
IDictionary<TWrapper, string> resultMap,
string defaultValue = null,
bool qualifyResult = false,
bool isNullable = false)
where TWrapper : EnumWrapper
{
string resultType = $"{GetTypeAlias<TValue>()}{(isNullable ? "?" : "")}";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatValue<TValue>(defaultValue)));
this.Write(";");
}
else if (expression.IsLiteral)
{
resultMap.TryGetValue(expression.LiteralValue, out string resultValue);
if (qualifyResult)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(".");
this.Write(this.ToStringHelper.ToStringWithCulture(resultValue));
this.Write(";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatValue<TValue>(resultValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,21 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateEnumExpressionTemplate.tt" once="true" #>
/// <summary>
/// Reset all the state for the targeted variable scope.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateEnumExpression<VariablesToClearWrapper, string>(this.Model.Variables, "targetScopeName", ScopeMap, isNullable: true); #>
await context.QueueClearScopeAsync(targetScopeName).ConfigureAwait(false);
return default;
}
}
@@ -1,25 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Frozen;
using System.Collections.Generic;
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class ClearAllVariablesTemplate
{
public ClearAllVariablesTemplate(ClearAllVariables model)
{
this.Model = this.Initialize(model);
}
public ClearAllVariables Model { get; }
public static readonly FrozenDictionary<VariablesToClearWrapper, string?> ScopeMap =
new Dictionary<VariablesToClearWrapper, string?>()
{
[VariablesToClearWrapper.Get(VariablesToClear.AllGlobalVariables)] = VariableScopeNames.Global,
[VariablesToClearWrapper.Get(VariablesToClear.ConversationScopedVariables)] = WorkflowFormulaState.DefaultScopeName,
}.ToFrozenDictionary();
}
@@ -1,339 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal abstract class CodeTemplate
{
private bool _endsWithNewline;
private string CurrentIndentField { get; set; } = string.Empty;
/// <summary>
/// Create the template output
/// </summary>
public abstract string TransformText();
#region Object Model helpers
public static string VariableName(PropertyPath path) => Throw.IfNull(path.VariableName);
public static string VariableScope(PropertyPath path) => Throw.IfNull(path.NamespaceAlias);
public static string FormatBoolValue(bool? value, bool defaultValue = false) =>
value ?? defaultValue ? "true" : "false";
public static string FormatStringValue(string? value)
{
if (value is null)
{
return "null";
}
if (value.Contains('\n') || value.Contains('\r'))
{
return @$"""""""{Environment.NewLine}{value}{Environment.NewLine}""""""";
}
if (value.Contains('"') || value.Contains('\\'))
{
return @$"""""""{value}""""""";
}
return @$"""{value}""";
}
public static string FormatValue<TValue>(string? value)
{
if (typeof(TValue) == typeof(string))
{
return FormatStringValue(value);
}
if (value is null)
{
return "null";
}
if (typeof(TValue).IsEnum)
{
return $"{typeof(TValue).Name}.{value}";
}
return $"{value}";
}
public static string FormatDataValue(DataValue value) =>
value switch
{
BlankDataValue => "null",
BooleanDataValue booleanValue => FormatBoolValue(booleanValue.Value),
FloatDataValue decimalValue => $"{decimalValue.Value}",
NumberDataValue numberValue => $"{numberValue.Value}",
DateDataValue dateValue => $"new DateTime({dateValue.Value.Ticks}, DateTimeKind.{dateValue.Value.Kind})",
DateTimeDataValue datetimeValue => $"new DateTimeOffset({datetimeValue.Value.Ticks}, TimeSpan.FromTicks({datetimeValue.Value.Offset}))",
TimeDataValue timeValue => $"TimeSpan.FromTicks({timeValue.Value.Ticks})",
StringDataValue stringValue => FormatStringValue(stringValue.Value),
OptionDataValue optionValue => @$"""{optionValue.Value}""",
// Indenting is important here to make the generated code readable. Don't change it without testing the output.
RecordDataValue recordValue =>
$"""
[
{string.Join(",\n ", recordValue.Properties.Select(p => $"[\"{p.Key}\"] = {FormatDataValue(p.Value)}"))}
]
""",
_ => throw new DeclarativeModelException($"Unable to format '{value.GetType().Name}'"),
};
public static TTarget FormatEnum<TSource, TTarget>(TSource value, IDictionary<TSource, TTarget> map, TTarget? defaultValue = default)
{
if (map.TryGetValue(value, out TTarget? target))
{
return target;
}
if (defaultValue is null)
{
throw new DeclarativeModelException($"No default value suppied for '{typeof(TTarget).Name}'");
}
return defaultValue;
}
public static string GetTypeAlias<TValue>() => GetTypeAlias(typeof(TValue));
public static string GetTypeAlias(Type type)
{
return type switch
{
Type t when t == typeof(bool) => "bool",
Type t when t == typeof(byte) => "byte",
Type t when t == typeof(sbyte) => "sbyte",
Type t when t == typeof(char) => "char",
Type t when t == typeof(decimal) => "decimal",
Type t when t == typeof(double) => "double",
Type t when t == typeof(float) => "float",
Type t when t == typeof(int) => "int",
Type t when t == typeof(uint) => "uint",
Type t when t == typeof(long) => "long",
Type t when t == typeof(ulong) => "ulong",
Type t when t == typeof(nint) => "nint",
Type t when t == typeof(nuint) => "nuint",
Type t when t == typeof(short) => "short",
Type t when t == typeof(ushort) => "ushort",
Type t when t == typeof(string) => "string",
Type t when t == typeof(object) => "object",
_ => type.Name
};
}
#endregion
#region Properties
/// <summary>
/// The string builder that generation-time code is using to assemble generated output
/// </summary>
public StringBuilder GenerationEnvironment
{
get
{
return field ??= new StringBuilder();
}
set;
}
/// <summary>
/// The error collection for the generation process
/// </summary>
public CompilerErrorCollection Errors => field ??= [];
/// <summary>
/// A list of the lengths of each indent that was added with PushIndent
/// </summary>
private List<int> IndentLengths { get => field ??= []; }
/// <summary>
/// Gets the current indent we use when adding lines to the output
/// </summary>
public string CurrentIndent
{
get
{
return this.CurrentIndentField;
}
}
/// <summary>
/// Current transformation session
/// </summary>
public virtual IDictionary<string, object>? Session { get; set; }
#endregion
#region Transform-time helpers
/// <summary>
/// Write text directly into the generated output
/// </summary>
public void Write(string textToAppend)
{
if (string.IsNullOrEmpty(textToAppend))
{
return;
}
// If we're starting off, or if the previous text ended with a newline,
// we have to append the current indent first.
if ((this.GenerationEnvironment.Length == 0)
|| this._endsWithNewline)
{
this.GenerationEnvironment.Append(this.CurrentIndentField);
this._endsWithNewline = false;
}
// Check if the current text ends with a newline
if (textToAppend.EndsWith(Environment.NewLine, StringComparison.CurrentCulture))
{
this._endsWithNewline = true;
}
// This is an optimization. If the current indent is "", then we don't have to do any
// of the more complex stuff further down.
if (this.CurrentIndentField.Length == 0)
{
this.GenerationEnvironment.Append(textToAppend);
return;
}
// Everywhere there is a newline in the text, add an indent after it
textToAppend = textToAppend.Replace(Environment.NewLine, Environment.NewLine + this.CurrentIndentField);
// If the text ends with a newline, then we should strip off the indent added at the very end
// because the appropriate indent will be added when the next time Write() is called
if (this._endsWithNewline)
{
this.GenerationEnvironment.Append(textToAppend, 0, textToAppend.Length - this.CurrentIndentField.Length);
}
else
{
this.GenerationEnvironment.Append(textToAppend);
}
}
/// <summary>
/// Write text directly into the generated output
/// </summary>
public void WriteLine(string textToAppend)
{
this.Write(textToAppend);
this.GenerationEnvironment.AppendLine();
this._endsWithNewline = true;
}
/// <summary>
/// Write formatted text directly into the generated output
/// </summary>
public void Write(string format, params object[] args)
{
this.Write(string.Format(CultureInfo.CurrentCulture, format, args));
}
/// <summary>
/// Write formatted text directly into the generated output
/// </summary>
public void WriteLine(string format, params object[] args)
{
this.WriteLine(string.Format(CultureInfo.CurrentCulture, format, args));
}
/// <summary>
/// Raise an error
/// </summary>
public void Error(string message)
{
CompilerError error = new()
{
ErrorText = message
};
this.Errors.Add(error);
}
/// <summary>
/// Raise a warning
/// </summary>
public void Warning(string message)
{
CompilerError error = new()
{
ErrorText = message,
IsWarning = true
};
error.ErrorText = message;
error.IsWarning = true;
this.Errors.Add(error);
}
/// <summary>
/// Increase the indent
/// </summary>
public void PushIndent(string indent)
{
if (indent is null)
{
throw new ArgumentNullException(nameof(indent));
}
this.CurrentIndentField += indent;
this.IndentLengths.Add(indent.Length);
}
/// <summary>
/// Remove the last indent that was added with PushIndent
/// </summary>
public string PopIndent()
{
string returnValue = string.Empty;
if (this.IndentLengths.Count > 0)
{
int indentLength = this.IndentLengths[this.IndentLengths.Count - 1];
this.IndentLengths.RemoveAt(this.IndentLengths.Count - 1);
if (indentLength > 0)
{
returnValue = this.CurrentIndentField.Substring(this.CurrentIndentField.Length - indentLength);
this.CurrentIndentField = this.CurrentIndentField.Remove(this.CurrentIndentField.Length - indentLength);
}
}
return returnValue;
}
/// <summary>
/// Remove any indentation
/// </summary>
public void ClearIndent()
{
this.IndentLengths.Clear();
this.CurrentIndentField = string.Empty;
}
#endregion
#region ToString Helpers
/// <summary>
/// Utility class to produce culture-oriented representation of an object as a string.
/// </summary>
public sealed class ToStringInstanceHelper
{
/// <summary>
/// This is called from the compile/run appdomain to convert objects within an expression block to a string
/// </summary>
#pragma warning disable CA1822 // Required to be non-static for use in generated code
public string ToStringWithCulture(object objectToConvert) => $"{objectToConvert}";
#pragma warning restore CA1822
}
/// <summary>
/// Helper to produce culture-oriented representation of an object as a string
/// </summary>
public ToStringInstanceHelper ToStringHelper { get; } = new();
#endregion
}
@@ -1,172 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class ConditionGroupTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Conditional branching similar to an if / elseif / elseif / els" +
"e chain.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
for (int index = 0; index < this.Model.Conditions.Length; ++index)
{
ConditionItem conditionItem = this.Model.Conditions[index];
if (conditionItem.Condition is null)
{
continue; // Skip if no condition is defined
}
EvaluateBoolExpression(conditionItem.Condition, $"condition{index}");
this.Write("\n if (condition");
this.Write(this.ToStringHelper.ToStringWithCulture(index));
this.Write(")\n {\n return \"");
this.Write(this.ToStringHelper.ToStringWithCulture(ConditionGroupExecutor.Steps.Item(this.Model, conditionItem)));
this.Write("\";\n }\n ");
}
this.Write("\n return \"");
this.Write(this.ToStringHelper.ToStringWithCulture(ConditionGroupExecutor.Steps.Else(this.Model)));
this.Write("\";\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateBoolExpression(BoolExpression expression, string targetVariable, bool defaultValue = false)
{
if (expression is null)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatBoolValue(defaultValue)));
this.Write(";");
}
else if (expression.IsLiteral)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatBoolValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<bool>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<bool>>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<bool>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,34 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.ObjectModel" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateBoolExpressionTemplate.tt" once="true" #>
/// <summary>
/// Conditional branching similar to an if / elseif / elseif / else chain.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
for (int index = 0; index < this.Model.Conditions.Length; ++index)
{
ConditionItem conditionItem = this.Model.Conditions[index];
if (conditionItem.Condition is null)
{
continue; // Skip if no condition is defined
}
EvaluateBoolExpression(conditionItem.Condition, $"condition{index}");#>
if (condition<#= index #>)
{
return "<#= ConditionGroupExecutor.Steps.Item(this.Model, conditionItem)#>";
}
<#
}
#>
return "<#= ConditionGroupExecutor.Steps.Else(this.Model)#>";
}
}
@@ -1,15 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class ConditionGroupTemplate
{
public ConditionGroupTemplate(ConditionGroup model)
{
this.Model = this.Initialize(model);
}
public ConditionGroup Model { get; }
}
@@ -1,324 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using Microsoft.Extensions.AI;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class CopyConversationMessagesTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Copies one or more messages into the specified agent conversat" +
"ion.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExe" +
"cutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
EvaluateStringExpression(this.Model.ConversationId, "conversationId", isNullable: true);
this.Write("\n if (string.IsNullOrWhiteSpace(conversationId))\n {\n thr" +
"ow new DeclarativeActionException($\"Conversation identifier must be defined: {th" +
"is.Id}\");\n }");
EvaluateValueExpression<ChatMessage[]>(this.Model.Messages, "messages");
this.Write(@"
if (messages is not null)
{
foreach (ChatMessage message in messages)
{
await agentProvider.CreateMessageAsync(conversationId, message, cancellationToken).ConfigureAwait(false);
}
}
return default;
}
}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateStringExpression(StringExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "string?" : "string";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(isNullable ? "null" : "string.Empty"));
this.Write(";");
}
else if (expression.IsLiteral)
{
if (expression.LiteralValue.Contains("\n"))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = \n \"\"\"\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.LiteralValue));
this.Write("\n \"\"\";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.LiteralValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<string>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateValueExpression(ValueExpression expression, string targetVariable) =>
EvaluateValueExpression<object>(expression, targetVariable);
void EvaluateValueExpression<TValue>(ValueExpression expression, string targetVariable)
{
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,33 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ import namespace="Microsoft.Extensions.AI" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateStringExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateValueExpressionTemplate.tt" once="true" #>
/// <summary>
/// Copies one or more messages into the specified agent conversation.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateStringExpression(this.Model.ConversationId, "conversationId", isNullable: true); #>
if (string.IsNullOrWhiteSpace(conversationId))
{
throw new DeclarativeActionException($"Conversation identifier must be defined: {this.Id}");
}<#
EvaluateValueExpression<ChatMessage[]>(this.Model.Messages, "messages");
#>
if (messages is not null)
{
foreach (ChatMessage message in messages)
{
await agentProvider.CreateMessageAsync(conversationId, message, cancellationToken).ConfigureAwait(false);
}
}
return default;
}
}
@@ -1,16 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class CopyConversationMessagesTemplate
{
public CopyConversationMessagesTemplate(CopyConversationMessages model)
{
this.Model = this.Initialize(model);
this.UseAgentProvider = true;
}
public CopyConversationMessages Model { get; }
}
@@ -1,78 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class CreateConversationTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Creates a new conversation and stores the identifier value to " +
"the \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.ConversationId));
this.Write("\" variable.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExe" +
"cutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write(@""", session)
{
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string conversationId = await agentProvider.CreateConversationAsync(cancellationToken).ConfigureAwait(false);");
AssignVariable(this.ConversationId, "conversationId");
this.Write("\n await context.AddEventAsync(new ConversationUpdateEvent(conversationId))" +
".ConfigureAwait(false);\n\n return default;\n }\n}\n");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
}
}
@@ -1,19 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
/// <summary>
/// Creates a new conversation and stores the identifier value to the "<#= this.Model.ConversationId #>" variable.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExecutor(id: "<#= this.Id #>", session)
{
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string conversationId = await agentProvider.CreateConversationAsync(cancellationToken).ConfigureAwait(false);<#
AssignVariable(this.ConversationId, "conversationId");#>
await context.AddEventAsync(new ConversationUpdateEvent(conversationId)).ConfigureAwait(false);
return default;
}
}
@@ -1,20 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class CreateConversationTemplate
{
public CreateConversationTemplate(CreateConversation model)
{
this.Model = this.Initialize(model);
this.ConversationId = Throw.IfNull(this.Model.ConversationId);
this.UseAgentProvider = true;
}
public CreateConversation Model { get; }
public PropertyPath ConversationId { get; }
}
@@ -1,40 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class DefaultTemplate : ActionTemplate, IModeledAction
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\nDelegateExecutor ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.InstanceVariable));
this.Write(" = new(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.RootVariable));
this.Write(".Session");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Action is not null ? $", {this.Action}" : ""));
this.Write(");\n");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,4 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate, IModeledAction" visibility="internal" linePragmas="false" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Interpreter" #>
<#@ assembly name="System.Core" #>
DelegateExecutor <#= this.InstanceVariable #> = new(id: "<#= this.Id #>", <#= this.RootVariable #>.Session<#= this.Action is not null ? $", {this.Action}" : "" #>);
@@ -1,21 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class DefaultTemplate
{
public DefaultTemplate(DialogAction model, string rootId, string? action = null)
{
this.Initialize(model);
this.Action = action;
this.InstanceVariable = this.Id.FormatName();
this.RootVariable = rootId.FormatName();
}
public string? Action { get; }
public string InstanceVariable { get; }
public string RootVariable { get; }
}
@@ -1,51 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class EdgeTemplate : CodeTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
if (this.Condition is not null)
{
this.Write("\n builder.AddEdge(");
this.Write(this.ToStringHelper.ToStringWithCulture(this.SourceId));
this.Write(", ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.TargetId));
this.Write(", (object? result) => ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Condition));
this.Write(");");
}
else
{
this.Write("\n builder.AddEdge(");
this.Write(this.ToStringHelper.ToStringWithCulture(this.SourceId));
this.Write(", ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.TargetId));
this.Write(");");
}
this.Write("\n");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,10 +0,0 @@
<#@ template language="C#" inherits="CodeTemplate" visibility="internal" linePragmas="false" #>
<#@ assembly name="System.Core" #>
<# if (this.Condition is not null)
{#>
builder.AddEdge(<#= this.SourceId #>, <#= this.TargetId #>, (object? result) => <#= this.Condition #>);<#
}
else
{#>
builder.AddEdge(<#= this.SourceId #>, <#= this.TargetId #>);<#
} #>
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class EdgeTemplate
{
public EdgeTemplate(string sourceId, string targetId, string? condition = null)
{
this.SourceId = sourceId.FormatName();
this.TargetId = targetId.FormatName();
this.Condition = condition;
}
public string SourceId { get; }
public string TargetId { get; }
public string? Condition { get; }
}
@@ -1,37 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class EditTableV2Template : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Modify items in a list\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,14 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
/// <summary>
/// Modify items in a list
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
return default;
}
}
@@ -1,15 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class EditTableV2Template
{
public EditTableV2Template(EditTableV2 model)
{
this.Model = this.Initialize(model);
}
public EditTableV2 Model { get; }
}
@@ -1,40 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class EmptyTemplate : CodeTemplate, IModeledAction
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\nDelegateExecutor ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.InstanceVariable));
this.Write(" = new(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.RootVariable));
this.Write(".Session");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Action is not null ? $", {this.Action}" : ""));
this.Write(");\n");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,4 +0,0 @@
<#@ template language="C#" inherits="CodeTemplate, IModeledAction" visibility="internal" linePragmas="false" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Interpreter" #>
<#@ assembly name="System.Core" #>
DelegateExecutor <#= this.InstanceVariable #> = new(id: "<#= this.Id #>", <#= this.RootVariable #>.Session<#= this.Action is not null ? $", {this.Action}" : "" #>);
@@ -1,23 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class EmptyTemplate
{
public EmptyTemplate(string actionId, string rootId, string? action = null)
{
this.Id = actionId;
this.Name = this.Id.FormatType();
this.InstanceVariable = this.Id.FormatName();
this.RootVariable = rootId.FormatName();
this.Action = action;
}
public string Id { get; }
public string Name { get; }
public string InstanceVariable { get; }
public string RootVariable { get; }
public string? Action { get; }
}
@@ -1,250 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class ForeachTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Loops over a list assignign the loop variable to \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.Value));
this.Write("\" variable.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write(@""", session)
{
private int _index;
private object[] _values = [];
public bool HasValue { get; private set; }
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
this._index = 0;");
EvaluateValueExpression(this.Model.Items, "evaluatedValue");
this.Write(@"
if (evaluatedValue == null)
{
this._values = [];
this.HasValue = false;
}
else
if (evaluatedValue is IEnumerable evaluatedList)
{
this._values = [.. evaluatedList];
}
else
{
this._values = [evaluatedValue];
}
await this.ResetAsync(context, cancellationToken).ConfigureAwait(false);
return default;
}
public async ValueTask TakeNextAsync(IWorkflowContext context, object? _, CancellationToken cancellationToken)
{
if (this.HasValue = this._index < this._values.Length)
{
object value = this._values[this._index];
");
AssignVariable(this.Value, "value", tightFormat: true);
if (this.Index is not null)
{
AssignVariable(this.Index, "this._index", tightFormat: true);
}
this.Write(@"
this._index++;
}
}
public async ValueTask CompleteAsync(IWorkflowContext context, object? _, CancellationToken cancellationToken)
{
await this.ResetAsync(context, cancellationToken).ConfigureAwait(false);
}
private async ValueTask ResetAsync(IWorkflowContext context, CancellationToken cancellationToken)
{");
AssignVariable(this.Value, "UnassignedValue.Instance", tightFormat: true);
if (this.Index is not null)
{
AssignVariable(this.Index, "UnassignedValue.Instance", tightFormat: true);
}
this.Write("\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateValueExpression(ValueExpression expression, string targetVariable) =>
EvaluateValueExpression<object>(expression, targetVariable);
void EvaluateValueExpression<TValue>(ValueExpression expression, string targetVariable)
{
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,77 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateValueExpressionTemplate.tt" once="true" #>
/// <summary>
/// Loops over a list assignign the loop variable to "<#= this.Model.Value #>" variable.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
private int _index;
private object[] _values = [];
public bool HasValue { get; private set; }
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
this._index = 0;<#
EvaluateValueExpression(this.Model.Items, "evaluatedValue");#>
if (evaluatedValue == null)
{
this._values = [];
this.HasValue = false;
}
else
if (evaluatedValue is IEnumerable evaluatedList)
{
this._values = [.. evaluatedList];
}
else
{
this._values = [evaluatedValue];
}
await this.ResetAsync(context, cancellationToken).ConfigureAwait(false);
return default;
}
public async ValueTask TakeNextAsync(IWorkflowContext context, object? _, CancellationToken cancellationToken)
{
if (this.HasValue = this._index < this._values.Length)
{
object value = this._values[this._index];
<#
AssignVariable(this.Value, "value", tightFormat: true);
if (this.Index is not null)
{
AssignVariable(this.Index, "this._index", tightFormat: true);
}
#>
this._index++;
}
}
public async ValueTask CompleteAsync(IWorkflowContext context, object? _, CancellationToken cancellationToken)
{
await this.ResetAsync(context, cancellationToken).ConfigureAwait(false);
}
private async ValueTask ResetAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
AssignVariable(this.Value, "UnassignedValue.Instance", tightFormat: true);
if (this.Index is not null)
{
AssignVariable(this.Index, "UnassignedValue.Instance", tightFormat: true);
}
#>
}
}
@@ -1,20 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class ForeachTemplate
{
public ForeachTemplate(Foreach model)
{
this.Model = this.Initialize(model);
this.Index = this.Model.Index?.Path;
this.Value = Throw.IfNull(this.Model.Value);
}
public Foreach Model { get; }
public PropertyPath? Index { get; }
public PropertyPath Value { get; }
}
@@ -1,38 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class InstanceTemplate : CodeTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write(this.ToStringHelper.ToStringWithCulture(this.ExecutorType));
this.Write("Executor ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.InstanceVariable));
this.Write(" = new(");
this.Write(this.ToStringHelper.ToStringWithCulture(this.RootVariable));
this.Write(".Session");
this.Write(this.ToStringHelper.ToStringWithCulture(this.HasProvider ? ", options.AgentProvider" : ""));
this.Write(");");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,3 +0,0 @@
<#@ template language="C#" inherits="CodeTemplate" visibility="internal" linePragmas="false" #>
<#@ assembly name="System.Core" #>
<#= this.ExecutorType #>Executor <#= this.InstanceVariable #> = new(<#= this.RootVariable #>.Session<#= this.HasProvider ? ", options.AgentProvider" : "" #>);
@@ -1,21 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class InstanceTemplate
{
public InstanceTemplate(string executorId, string rootId, bool hasProvider = false)
{
this.InstanceVariable = executorId.FormatName();
this.ExecutorType = executorId.FormatType();
this.RootVariable = rootId.FormatName();
this.HasProvider = hasProvider;
}
public string InstanceVariable { get; }
public string ExecutorType { get; }
public string RootVariable { get; }
public bool HasProvider { get; }
}
@@ -1,415 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System.Collections.Generic;
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.ObjectModel;
using Microsoft.Extensions.AI;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class InvokeAzureAgentTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Invokes an agent to process messages and return a response wit" +
"hin a conversation context.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session, ResponseAgentProvider agentProvider) : AgentExec" +
"utor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session, agentProvider)\n{\n // <inheritdoc />\n protected override async V" +
"alueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cance" +
"llationToken)\n {");
EvaluateStringExpression(this.Model.Agent.Name, "agentName", isNullable: true);
this.Write("\n\n if (string.IsNullOrWhiteSpace(agentName))\n {\n throw n" +
"ew DeclarativeActionException($\"Agent name must be defined: {this.Id}\");\n " +
" }\n ");
EvaluateStringExpression(this.Model.ConversationId, "conversationId", isNullable: true);
EvaluateBoolExpression(this.Model.Output?.AutoSend, "autoSend", defaultValue: true);
EvaluateListExpression<ChatMessage>(this.Model.Input?.Messages, "inputMessages");
this.Write(@"
AgentResponse agentResponse =
await InvokeAgentAsync(
context,
agentName,
conversationId,
autoSend,
inputMessages,
cancellationToken).ConfigureAwait(false);
if (autoSend)
{
await context.AddEventAsync(new AgentResponseEvent(this.Id, agentResponse)).ConfigureAwait(false);
}
");
AssignVariable(this.Messages, "agentResponse.Messages");
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateBoolExpression(BoolExpression expression, string targetVariable, bool defaultValue = false)
{
if (expression is null)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatBoolValue(defaultValue)));
this.Write(";");
}
else if (expression.IsLiteral)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatBoolValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<bool>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<bool>>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n bool ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<bool>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateListExpression<TElement>(ValueExpression expression, string targetVariable)
{
string typeName = GetTypeAlias<TElement>();
if (expression is null)
{
this.Write("\n IList<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n IList<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n IList<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadListAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TElement>()));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n IList<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write("> = await context.EvaluateListAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n IList<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateListAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateStringExpression(StringExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "string?" : "string";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(isNullable ? "null" : "string.Empty"));
this.Write(";");
}
else if (expression.IsLiteral)
{
if (expression.LiteralValue.Contains("\n"))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = \n \"\"\"\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.LiteralValue));
this.Write("\n \"\"\";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.LiteralValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<string>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,48 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ import namespace="Microsoft.Extensions.AI" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateBoolExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateListExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateStringExpressionTemplate.tt" once="true" #>
/// <summary>
/// Invokes an agent to process messages and return a response within a conversation context.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session, ResponseAgentProvider agentProvider) : AgentExecutor(id: "<#= this.Id #>", session, agentProvider)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateStringExpression(this.Model.Agent.Name, "agentName", isNullable: true);#>
if (string.IsNullOrWhiteSpace(agentName))
{
throw new DeclarativeActionException($"Agent name must be defined: {this.Id}");
}
<#
EvaluateStringExpression(this.Model.ConversationId, "conversationId", isNullable: true);
EvaluateBoolExpression(this.Model.Output?.AutoSend, "autoSend", defaultValue: true);
EvaluateListExpression<ChatMessage>(this.Model.Input?.Messages, "inputMessages");#>
AgentResponse agentResponse =
await InvokeAgentAsync(
context,
agentName,
conversationId,
autoSend,
inputMessages,
cancellationToken).ConfigureAwait(false);
if (autoSend)
{
await context.AddEventAsync(new AgentResponseEvent(this.Id, agentResponse)).ConfigureAwait(false);
}
<#
AssignVariable(this.Messages, "agentResponse.Messages"); #>
return default;
}
}
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class InvokeAzureAgentTemplate
{
public InvokeAzureAgentTemplate(InvokeAzureAgent model)
{
this.Model = this.Initialize(model);
this.Messages = this.Model.Output?.Messages?.Path;
this.UseAgentProvider = true;
}
public InvokeAzureAgent Model { get; }
public PropertyPath? Messages { get; }
}
@@ -1,99 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class ParseValueTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Parses a string or untyped value to the provided data type. Wh" +
"en the input is a string, it will be treated as JSON.\n/// </summary>\ninternal se" +
"aled class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" { \n VariableType targetType = ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.GetVariableType()));
this.Write(";");
if (this.Model.Value.IsVariableReference && this.Model.Value.VariableReference.SegmentCount == 2)
{
this.Write("\n object? parsedValue = await context.ConvertValueAsync(targetType, key: \"" +
"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.Value.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.Value.VariableReference.NamespaceAlias));
this.Write("\", cancellationToken).ConfigureAwait(false);");
}
else if (this.Model.Value.IsVariableReference)
{
this.Write("\n object? parsedValue = await context.ConvertValueAsync(targetType, ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(this.Model.Value.VariableReference.ToString())));
this.Write(", cancellationToken).ConfigureAwait(false);");
}
else
{
this.Write("\n object? parsedValue = await context.ConvertValueAsync(targetType, ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(this.Model.Value.ExpressionText)));
this.Write(", cancellationToken).ConfigureAwait(false);");
}
AssignVariable(this.Variable, "parsedValue");
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
}
}
@@ -1,30 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
/// <summary>
/// Parses a string or untyped value to the provided data type. When the input is a string, it will be treated as JSON.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
VariableType targetType = <#= this.GetVariableType() #>;<#
if (this.Model.Value.IsVariableReference && this.Model.Value.VariableReference.SegmentCount == 2)
{#>
object? parsedValue = await context.ConvertValueAsync(targetType, key: "<#= this.Model.Value.VariableReference.VariableName #>", scopeName: "<#= this.Model.Value.VariableReference.NamespaceAlias #>", cancellationToken).ConfigureAwait(false);<#
}
else if (this.Model.Value.IsVariableReference)
{#>
object? parsedValue = await context.ConvertValueAsync(targetType, <#= FormatStringValue(this.Model.Value.VariableReference.ToString()) #>, cancellationToken).ConfigureAwait(false);<#
}
else
{#>
object? parsedValue = await context.ConvertValueAsync(targetType, <#= FormatStringValue(this.Model.Value.ExpressionText) #>, cancellationToken).ConfigureAwait(false);<#
}
AssignVariable(this.Variable, "parsedValue"); #>
return default;
}
}
@@ -1,40 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Linq;
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class ParseValueTemplate
{
public ParseValueTemplate(ParseValue model)
{
this.Model = this.Initialize(model);
this.Variable = Throw.IfNull(this.Model.Variable);
}
public ParseValue Model { get; }
public PropertyPath Variable { get; }
private string GetVariableType()
{
return GetVariableType(this.Model.ValueType);
static string GetVariableType(DataType? dataType) =>
dataType switch
{
null => "null",
StringDataType => "typeof(string)",
BooleanDataType => "typeof(bool)",
FloatDataType => "typeof(double)",
NumberDataType => "typeof(decimal)",
DateTimeDataType => "typeof(DateTime)",
DateDataType => "typeof(DateTime)",
TimeDataType => "typeof(TimeSpan)",
RecordDataType recordType => $"\nVariableType.Record(\n{string.Join(",\n ", recordType.Properties.Select(property => @$"( ""{property.Key}"", {GetVariableType(property.Value.Type)} )"))})",
TableDataType tableType => $"\nVariableType.Record(\n{string.Join(",\n ", tableType.Properties.Select(property => @$"( ""{property.Key}"", {GetVariableType(property.Value.Type)} )"))})",
_ => throw new DeclarativeModelException($"Unsupported data type: {dataType}"),
};
}
}
@@ -1,118 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class ProviderTemplate : CodeTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write(@"
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// </auto-generated>
// ------------------------------------------------------------------------------
#nullable enable
#pragma warning disable IDE0005 // Extra using directive is ok.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Extensions.AI;
");
if (this.Namespace is not null)
{
this.Write("\nnamespace ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Namespace));
this.Write(";\n");
}
this.Write(@"
/// <summary>
/// This class provides a factory method to create a <see cref=""Workflow"" /> instance.
/// </summary>
/// <remarks>
/// The workflow defined here was generated from a declarative workflow definition.
/// Declarative workflows utilize Power FX for defining conditions and expressions.
/// To learn more about Power FX, see:
/// https://learn.microsoft.com/power-platform/power-fx/formula-reference-copilot-studio
/// </remarks>
public static class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Prefix ?? string.Empty));
this.Write("WorkflowProvider\n{");
foreach (string executor in ByLine(this.Executors, formatGroup: true))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(executor));
}
this.Write(@"
public static Workflow CreateWorkflow<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage>? inputTransform = null)
where TInput : notnull
{
// Create root executor to initialize the workflow.
inputTransform ??= (message) => DeclarativeWorkflowBuilder.DefaultTransform(message);
");
this.Write(this.ToStringHelper.ToStringWithCulture(this.RootExecutorType));
this.Write("Executor<TInput> ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.RootInstance));
this.Write(" = new(options, inputTransform);");
// Create executor instances
foreach (string instance in ByLine(this.Instances))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(instance));
}
this.Write("\n\n // Define the workflow builder\n WorkflowBuilder builder = new(");
this.Write(this.ToStringHelper.ToStringWithCulture(this.RootInstance));
this.Write(");\n\n // Connect executors");
foreach (string edge in ByLine(this.Edges))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(edge));
}
this.Write("\n\n // Build the workflow\n return builder.Build(validateOrphans: fal" +
"se);\n }\n}\n");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,75 +0,0 @@
<#@ template language="C#" inherits="CodeTemplate" visibility="internal" linePragmas="false" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ assembly name="System.Core" #>
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// </auto-generated>
// ------------------------------------------------------------------------------
#nullable enable
#pragma warning disable IDE0005 // Extra using directive is ok.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Extensions.AI;
<#
if (this.Namespace is not null)
{#>
namespace <#= this.Namespace #>;
<#
}
#>
/// <summary>
/// This class provides a factory method to create a <see cref="Workflow" /> instance.
/// </summary>
/// <remarks>
/// The workflow defined here was generated from a declarative workflow definition.
/// Declarative workflows utilize Power FX for defining conditions and expressions.
/// To learn more about Power FX, see:
/// https://learn.microsoft.com/power-platform/power-fx/formula-reference-copilot-studio
/// </remarks>
public static class <#= this.Prefix ?? string.Empty #>WorkflowProvider
{<#
foreach (string executor in ByLine(this.Executors, formatGroup: true))
{ #>
<#= executor #><#
}
#>
public static Workflow CreateWorkflow<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage>? inputTransform = null)
where TInput : notnull
{
// Create root executor to initialize the workflow.
inputTransform ??= (message) => DeclarativeWorkflowBuilder.DefaultTransform(message);
<#= this.RootExecutorType #>Executor<TInput> <#= this.RootInstance #> = new(options, inputTransform);<#
// Create executor instances
foreach (string instance in ByLine(this.Instances))
{ #>
<#= instance #><#
}#>
// Define the workflow builder
WorkflowBuilder builder = new(<#= this.RootInstance #>);
// Connect executors<#
foreach (string edge in ByLine(this.Edges))
{ #>
<#= edge #><#
}
#>
// Build the workflow
return builder.Build(validateOrphans: false);
}
}
@@ -1,48 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class ProviderTemplate
{
public ProviderTemplate(
string workflowId,
IEnumerable<string> executors,
IEnumerable<string> instances,
IEnumerable<string> edges)
{
this.Executors = executors;
this.Instances = instances;
this.Edges = edges;
this.RootInstance = workflowId.FormatName();
this.RootExecutorType = workflowId.FormatType();
}
public string? Namespace { get; init; }
public string? Prefix { get; init; }
public string RootInstance { get; }
public string RootExecutorType { get; }
public IEnumerable<string> Executors { get; }
public IEnumerable<string> Instances { get; }
public IEnumerable<string> Edges { get; }
public static IEnumerable<string> ByLine(IEnumerable<string> templates, bool formatGroup = false)
{
foreach (string template in templates)
{
foreach (string line in template.ByLine())
{
yield return line;
}
if (formatGroup)
{
yield return string.Empty;
}
}
}
}
@@ -1,37 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class QuestionTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Request input.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,14 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
/// <summary>
/// Request input.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
return default;
}
}
@@ -1,15 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class QuestionTemplate
{
public QuestionTemplate(Question model)
{
this.Model = this.Initialize(model);
}
public Question Model { get; }
}
@@ -1,74 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class ResetVariableTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Resets the value of the \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.Variable));
this.Write("\" variable, potentially causing re-evaluation \n/// of the default value, question" +
" or action that provides the value to this variable.\n/// </summary>\ninternal sea" +
"led class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n protected override async ValueTask<object?> ExecuteAsync(IWorkf" +
"lowContext context, CancellationToken cancellationToken)\n {");
AssignVariable(this.Variable, "UnassignedValue.Instance");
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
}
}
@@ -1,17 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
/// <summary>
/// Resets the value of the "<#= this.Model.Variable #>" variable, potentially causing re-evaluation
/// of the default value, question or action that provides the value to this variable.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
AssignVariable(this.Variable, "UnassignedValue.Instance"); #>
return default;
}
}
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class ResetVariableTemplate
{
public ResetVariableTemplate(ResetVariable model)
{
this.Model = this.Initialize(model);
this.Variable = Throw.IfNull(this.Model.Variable);
}
public ResetVariable Model { get; }
public PropertyPath Variable { get; }
}
@@ -1,310 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class RetrieveConversationMessageTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Retrieves a list of messages from an agent conversation.\n/// <" +
"/summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExe" +
"cutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
EvaluateStringExpression(this.Model.ConversationId, "conversationId");
EvaluateStringExpression(this.Model.MessageId, "messageId");
this.Write("\n ChatMessage message = await agentProvider.GetMessageAsync(conversationId" +
", messageId, cancellationToken).ConfigureAwait(false);");
AssignVariable(this.Model.Message, "message");
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateRecordExpression<TValue>(ObjectExpression<RecordDataValue> expression, string targetVariable)
{
string resultTypeName = $"Dictionary<string, {GetTypeAlias<TValue>()}?>?";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" =\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateExpressionAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateExpressionAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateStringExpression(StringExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "string?" : "string";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(isNullable ? "null" : "string.Empty"));
this.Write(";");
}
else if (expression.IsLiteral)
{
if (expression.LiteralValue.Contains("\n"))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = \n \"\"\"\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.LiteralValue));
this.Write("\n \"\"\";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.LiteralValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<string>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,23 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateRecordExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateStringExpressionTemplate.tt" once="true" #>
/// <summary>
/// Retrieves a list of messages from an agent conversation.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateStringExpression(this.Model.ConversationId, "conversationId");
EvaluateStringExpression(this.Model.MessageId, "messageId"); #>
ChatMessage message = await agentProvider.GetMessageAsync(conversationId, messageId, cancellationToken).ConfigureAwait(false);<#
AssignVariable(this.Model.Message, "message");
#>
return default;
}
}
@@ -1,16 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class RetrieveConversationMessageTemplate
{
public RetrieveConversationMessageTemplate(RetrieveConversationMessage model)
{
this.Model = this.Initialize(model);
this.UseAgentProvider = true;
}
public RetrieveConversationMessage Model { get; }
}
@@ -1,584 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using System.Collections.Generic;
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class RetrieveConversationMessagesTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Retrieves a specific message from an agent conversation.\n/// <" +
"/summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExe" +
"cutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
EvaluateStringExpression(this.Model.ConversationId, "conversationId");
EvaluateIntExpression(this.Model.Limit, "limit");
EvaluateStringExpression(this.Model.MessageAfter, "after", isNullable: true);
EvaluateStringExpression(this.Model.MessageBefore, "before", isNullable: true);
EvaluateEnumExpression<AgentMessageSortOrderWrapper, bool>(this.Model.SortOrder, "newestFirst", SortMap, defaultValue: DefaultSort);
this.Write(@"
IAsyncEnumerable<ChatMessage> messagesResult =
agentProvider.GetMessagesAsync(
conversationId,
limit,
after,
before,
newestFirst,
cancellationToken);
List<ChatMessage> messages = [];
await foreach (ChatMessage message in messagesResult.ConfigureAwait(false))
{
messages.Add(message);
}");
AssignVariable(this.Model.Messages, "messages");
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateEnumExpression<TWrapper, TValue>(
EnumExpression<TWrapper> expression,
string targetVariable,
IDictionary<TWrapper, string> resultMap,
string defaultValue = null,
bool qualifyResult = false,
bool isNullable = false)
where TWrapper : EnumWrapper
{
string resultType = $"{GetTypeAlias<TValue>()}{(isNullable ? "?" : "")}";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatValue<TValue>(defaultValue)));
this.Write(";");
}
else if (expression.IsLiteral)
{
resultMap.TryGetValue(expression.LiteralValue, out string resultValue);
if (qualifyResult)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(".");
this.Write(this.ToStringHelper.ToStringWithCulture(resultValue));
this.Write(";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatValue<TValue>(resultValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultType));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateIntExpression(IntExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "int?" : "int";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(isNullable ? "null" : "0"));
this.Write(";");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.LiteralValue));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<int>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateRecordExpression<TValue>(ObjectExpression<RecordDataValue> expression, string targetVariable)
{
string resultTypeName = $"Dictionary<string, {GetTypeAlias<TValue>()}?>?";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" =\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateExpressionAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateExpressionAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(resultTypeName));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
void EvaluateStringExpression(StringExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "string?" : "string";
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(isNullable ? "null" : "string.Empty"));
this.Write(";");
}
else if (expression.IsLiteral)
{
if (expression.LiteralValue.Contains("\n"))
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = \n \"\"\"\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.LiteralValue));
this.Write("\n \"\"\";");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.LiteralValue)));
this.Write(";");
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<string>(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeName));
this.Write(" ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<string>(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,42 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateEnumExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateIntExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateRecordExpressionTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateStringExpressionTemplate.tt" once="true" #>
/// <summary>
/// Retrieves a specific message from an agent conversation.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session, ResponseAgentProvider agentProvider) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateStringExpression(this.Model.ConversationId, "conversationId");
EvaluateIntExpression(this.Model.Limit, "limit");
EvaluateStringExpression(this.Model.MessageAfter, "after", isNullable: true);
EvaluateStringExpression(this.Model.MessageBefore, "before", isNullable: true);
EvaluateEnumExpression<AgentMessageSortOrderWrapper, bool>(this.Model.SortOrder, "newestFirst", SortMap, defaultValue: DefaultSort); #>
IAsyncEnumerable<ChatMessage> messagesResult =
agentProvider.GetMessagesAsync(
conversationId,
limit,
after,
before,
newestFirst,
cancellationToken);
List<ChatMessage> messages = [];
await foreach (ChatMessage message in messagesResult.ConfigureAwait(false))
{
messages.Add(message);
}<#
AssignVariable(this.Model.Messages, "messages");
#>
return default;
}
}
@@ -1,27 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Frozen;
using System.Collections.Generic;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class RetrieveConversationMessagesTemplate
{
public RetrieveConversationMessagesTemplate(RetrieveConversationMessages model)
{
this.Model = this.Initialize(model);
this.UseAgentProvider = true;
}
public RetrieveConversationMessages Model { get; }
public const string DefaultSort = "false";
public static readonly FrozenDictionary<AgentMessageSortOrderWrapper, string> SortMap =
new Dictionary<AgentMessageSortOrderWrapper, string>()
{
[AgentMessageSortOrderWrapper.Get(AgentMessageSortOrder.NewestFirst)] = "true",
[AgentMessageSortOrderWrapper.Get(AgentMessageSortOrder.OldestFirst)] = "false",
}.ToFrozenDictionary();
}
@@ -1,79 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class RootTemplate : CodeTemplate, IModeledAction
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// The root executor for a declarative workflow.\n/// </summary>\ni" +
"nternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.TypeName));
this.Write("Executor<TInput>(\n DeclarativeWorkflowOptions options,\n Func<TInput, ChatMe" +
"ssage> inputTransform) :\n RootExecutor<TInput>(\"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", options, inputTransform)\n where TInput : notnull\n{\n protected override a" +
"sync ValueTask ExecuteAsync(TInput message, IWorkflowContext context, Cancellati" +
"onToken cancellationToken)\n {");
if (this.TypeInfo.EnvironmentVariables.Count > 0)
{
this.Write("\n // Set environment variables\n await this.InitializeEnvironmentAsy" +
"nc(\n context,");
int index = this.TypeInfo.EnvironmentVariables.Count - 1;
foreach (string variableName in this.TypeInfo.EnvironmentVariables)
{
this.Write("\n \"");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write("\"");
this.Write(this.ToStringHelper.ToStringWithCulture(index > 0 ? "," : ""));
--index;
}
this.Write(").ConfigureAwait(false);\n");
}
if (this.TypeInfo.UserVariables.Count > 0)
{
this.Write("\n // Initialize variables");
foreach (VariableInformationDiagnostic variableInfo in this.TypeInfo.UserVariables)
{
this.Write("\n await context.QueueStateUpdateAsync(\"");
this.Write(this.ToStringHelper.ToStringWithCulture(variableInfo.Path.VariableName));
this.Write("\", UnassignedValue.Instance, \"");
this.Write(this.ToStringHelper.ToStringWithCulture(variableInfo.Path.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
}
this.Write("\n }\n}\n");
return this.GenerationEnvironment.ToString();
}
}
}
@@ -1,40 +0,0 @@
<#@ template language="C#" inherits="CodeTemplate, IModeledAction" visibility="internal" linePragmas="false" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Interpreter" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ assembly name="System.Core" #>
/// <summary>
/// The root executor for a declarative workflow.
/// </summary>
internal sealed class <#= this.TypeName #>Executor<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage> inputTransform) :
RootExecutor<TInput>("<#= this.Id #>", options, inputTransform)
where TInput : notnull
{
protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
{<#
if (this.TypeInfo.EnvironmentVariables.Count > 0)
{ #>
// Set environment variables
await this.InitializeEnvironmentAsync(
context,<#
int index = this.TypeInfo.EnvironmentVariables.Count - 1;
foreach (string variableName in this.TypeInfo.EnvironmentVariables)
{#>
"<#= variableName #>"<#= index > 0 ? "," : "" #><#
--index;
}#>).ConfigureAwait(false);
<#}
if (this.TypeInfo.UserVariables.Count > 0)
{
#>
// Initialize variables<#
foreach (VariableInformationDiagnostic variableInfo in this.TypeInfo.UserVariables)
{#>
await context.QueueStateUpdateAsync("<#= variableInfo.Path.VariableName #>", UnassignedValue.Instance, "<#= variableInfo.Path.NamespaceAlias #>").ConfigureAwait(false);<#
}
}#>
}
}
@@ -1,22 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class RootTemplate
{
internal RootTemplate(
string workflowId,
WorkflowTypeInfo typeInfo)
{
this.Id = workflowId;
this.TypeInfo = typeInfo;
this.TypeName = workflowId.FormatType();
}
public string Id { get; }
public WorkflowTypeInfo TypeInfo { get; }
public string TypeName { get; }
}
@@ -1,109 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class SendActivityTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Formats a message template and sends an activity event.\n/// </" +
"summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" { ");
if (this.Model.Activity is MessageActivityTemplate messageActivity)
{
this.Write("\n string activityText = \n await context.FormatTemplateAsync( ");
foreach (TemplateLine line in messageActivity.Text)
{
this.Write("\n \"\"\"");
foreach (string text in line.ToTemplateString().ByLine())
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(text));
}
this.Write("\n \"\"\"");
}
this.Write("\n );\n AgentResponse response = new([new ChatMessage(ChatRole.As" +
"sistant, activityText)]);\n await context.AddEventAsync(new AgentResponseE" +
"vent(this.Id, response)).ConfigureAwait(false);");
}
this.Write("\n\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void EvaluateMessageTemplate(TemplateLine templateLine, string variableName)
{
if (templateLine is not null)
{
this.Write("\n string ");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write(" =\n await context.FormatTemplateAsync(\n \"\"\"");
FormatMessageTemplate(templateLine);
this.Write("\n \"\"\");");
}
else
{
this.Write("\n string? ");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write(" = null;");
}
}
void FormatMessageTemplate(TemplateLine line)
{
foreach (string text in line.ToTemplateString().ByLine())
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(text));
}
}
}
}
@@ -1,36 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/FormatMessageTemplate.tt" once="true" #>
/// <summary>
/// Formats a message template and sends an activity event.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{ <#
if (this.Model.Activity is MessageActivityTemplate messageActivity)
{ #>
string activityText =
await context.FormatTemplateAsync( <#
foreach (TemplateLine line in messageActivity.Text)
{ #>
"""<#
foreach (string text in line.ToTemplateString().ByLine())
{ #>
<#= text #><#
} #>
"""<#
}
#>
);
AgentResponse response = new([new ChatMessage(ChatRole.Assistant, activityText)]);
await context.AddEventAsync(new AgentResponseEvent(this.Id, response)).ConfigureAwait(false);<#
} #>
return default;
}
}
@@ -1,15 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class SendActivityTemplate
{
public SendActivityTemplate(SendActivity model)
{
this.Model = this.Initialize(model);
}
public SendActivity Model { get; }
}
@@ -1,195 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class SetMultipleVariablesTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Assigns an evaluated expression, other variable, or literal va" +
"lue to one or more variables.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
int index = 0;
foreach (var assignment in this.Model.Assignments)
{
// Separate assigments with a blank line for readability
if (index > 0)
{
this.Write("\n ");
}
++index;
EvaluateValueExpression(assignment.Value, $"evaluatedValue{index}");
AssignVariable(assignment.Variable, $"evaluatedValue{index}");
}
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateValueExpression(ValueExpression expression, string targetVariable) =>
EvaluateValueExpression<object>(expression, targetVariable);
void EvaluateValueExpression<TValue>(ValueExpression expression, string targetVariable)
{
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,29 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateValueExpressionTemplate.tt" once="true" #>
/// <summary>
/// Assigns an evaluated expression, other variable, or literal value to one or more variables.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<# int index = 0;
foreach (var assignment in this.Model.Assignments)
{
// Separate assigments with a blank line for readability
if (index > 0)
{#>
<#
}
++index;
EvaluateValueExpression(assignment.Value, $"evaluatedValue{index}");
AssignVariable(assignment.Variable, $"evaluatedValue{index}");
}
#>
return default;
}
}
@@ -1,15 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class SetMultipleVariablesTemplate
{
public SetMultipleVariablesTemplate(SetMultipleVariables model)
{
this.Model = this.Initialize(model);
}
public SetMultipleVariables Model { get; }
}
@@ -1,117 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class SetTextVariableTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Assigns an evaluated message template to the \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.Variable));
this.Write("\" variable.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n protected override async ValueTask<object?> ExecuteAsync(IWorkf" +
"lowContext context, CancellationToken cancellationToken)\n {");
EvaluateMessageTemplate(this.Model.Value, "textValue");
AssignVariable(this.Variable, "textValue");
this.Write("\n return default;\n }\n}");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateMessageTemplate(TemplateLine templateLine, string variableName)
{
if (templateLine is not null)
{
this.Write("\n string ");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write(" =\n await context.FormatTemplateAsync(\n \"\"\"");
FormatMessageTemplate(templateLine);
this.Write("\n \"\"\");");
}
else
{
this.Write("\n string? ");
this.Write(this.ToStringHelper.ToStringWithCulture(variableName));
this.Write(" = null;");
}
}
void FormatMessageTemplate(TemplateLine line)
{
foreach (string text in line.ToTemplateString().ByLine())
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(text));
}
}
}
}
@@ -1,19 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.AI.Workflows.Declarative.Extensions" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/FormatMessageTemplate.tt" once="true" #>
/// <summary>
/// Assigns an evaluated message template to the "<#= this.Model.Variable #>" variable.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateMessageTemplate(this.Model.Value, "textValue");
AssignVariable(this.Variable, "textValue"); #>
return default;
}
}
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class SetTextVariableTemplate
{
public SetTextVariableTemplate(SetTextVariable model)
{
this.Model = this.Initialize(model);
this.Variable = Throw.IfNull(this.Model.Variable);
}
public SetTextVariable Model { get; }
public PropertyPath Variable { get; }
}
@@ -1,186 +0,0 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
{
using Microsoft.Agents.ObjectModel;
using System;
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
internal partial class SetVariableTemplate : ActionTemplate
{
/// <summary>
/// Create the template output
/// </summary>
public override string TransformText()
{
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("\n/// <summary>\n/// Assigns an evaluated expression, other variable, or literal va" +
"lue to the \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Model.Variable));
this.Write("\" variable.\n/// </summary>\ninternal sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Name));
this.Write("Executor(FormulaSession session) : ActionExecutor(id: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(this.Id));
this.Write("\", session)\n{\n // <inheritdoc />\n protected override async ValueTask<object" +
"?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)\n " +
" {");
EvaluateValueExpression(this.Model.Value, "evaluatedValue");
AssignVariable(this.Variable, "evaluatedValue");
this.Write("\n return default;\n }\n}\n");
return this.GenerationEnvironment.ToString();
}
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{
this.Write("\n await context.QueueStateUpdateAsync(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableName(targetVariable)));
this.Write("\", value: ");
this.Write(this.ToStringHelper.ToStringWithCulture(valueVariable));
this.Write(", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(VariableScope(targetVariable)));
this.Write("\").ConfigureAwait(false);");
if (!tightFormat)
{
this.Write("\n ");
}
}
}
void EvaluateValueExpression(ValueExpression expression, string targetVariable) =>
EvaluateValueExpression<object>(expression, targetVariable);
void EvaluateValueExpression<TValue>(ValueExpression expression, string targetVariable)
{
if (expression is null)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = null;");
}
else if (expression.IsLiteral)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = ");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatDataValue(expression.LiteralValue)));
this.Write(";");
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.ReadStateAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(key: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.VariableName));
this.Write("\", scopeName: \"");
this.Write(this.ToStringHelper.ToStringWithCulture(expression.VariableReference.NamespaceAlias));
this.Write("\").ConfigureAwait(false);");
}
else if (expression.IsVariableReference)
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.VariableReference.ToString())));
this.Write(").ConfigureAwait(false);");
}
else
{
this.Write("\n ");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write("? ");
this.Write(this.ToStringHelper.ToStringWithCulture(targetVariable));
this.Write(" = await context.EvaluateValueAsync<");
this.Write(this.ToStringHelper.ToStringWithCulture(GetTypeAlias<TValue>()));
this.Write(">(");
this.Write(this.ToStringHelper.ToStringWithCulture(FormatStringValue(expression.ExpressionText)));
this.Write(").ConfigureAwait(false);");
}
}
}
}
@@ -1,19 +0,0 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="Microsoft.Agents.ObjectModel" #>
<#@ include file="Snippets/AssignVariableTemplate.tt" once="true" #>
<#@ include file="Snippets/EvaluateValueExpressionTemplate.tt" once="true" #>
/// <summary>
/// Assigns an evaluated expression, other variable, or literal value to the "<#= this.Model.Variable #>" variable.
/// </summary>
internal sealed class <#= this.Name #>Executor(FormulaSession session) : ActionExecutor(id: "<#= this.Id #>", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{<#
EvaluateValueExpression(this.Model.Value, "evaluatedValue");
AssignVariable(this.Variable, "evaluatedValue"); #>
return default;
}
}
@@ -1,18 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.ObjectModel;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
internal partial class SetVariableTemplate
{
internal SetVariableTemplate(SetVariable model)
{
this.Model = this.Initialize(model);
this.Variable = Throw.IfNull(this.Model.Variable);
}
public SetVariable Model { get; }
public PropertyPath Variable { get; }
}
@@ -1,12 +0,0 @@
<#+
void AssignVariable(PropertyPath targetVariable, string valueVariable, bool tightFormat = false)
{
if (targetVariable is not null)
{#>
await context.QueueStateUpdateAsync(key: "<#= VariableName(targetVariable) #>", value: <#= valueVariable #>, scopeName: "<#= VariableScope(targetVariable) #>").ConfigureAwait(false);<#+
if (!tightFormat)
{#>
<#+}
}
}
#>
@@ -1,25 +0,0 @@
<#+
void EvaluateBoolExpression(BoolExpression expression, string targetVariable, bool defaultValue = false)
{
if (expression is null)
{#>
bool <#= targetVariable #> = <#= FormatBoolValue(defaultValue) #>;<#+
}
else if (expression.IsLiteral)
{#>
bool <#= targetVariable #> = <#= FormatBoolValue(expression.LiteralValue) #>;<#+
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
bool <#= targetVariable #> = await context.ReadStateAsync<bool>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
bool <#= targetVariable #> = await context.EvaluateValueAsync<bool>>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
bool <#= targetVariable #> = await context.EvaluateValueAsync<bool>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,41 +0,0 @@
<#+
void EvaluateEnumExpression<TWrapper, TValue>(
EnumExpression<TWrapper> expression,
string targetVariable,
IDictionary<TWrapper, string> resultMap,
string defaultValue = null,
bool qualifyResult = false,
bool isNullable = false)
where TWrapper : EnumWrapper
{
string resultType = $"{GetTypeAlias<TValue>()}{(isNullable ? "?" : "")}";
if (expression is null)
{#>
<#= resultType #> <#= targetVariable #> = <#= FormatValue<TValue>(defaultValue) #>;<#+
}
else if (expression.IsLiteral)
{
resultMap.TryGetValue(expression.LiteralValue, out string resultValue);
if (qualifyResult)
{#>
<#= resultType #> <#= targetVariable #> = <#= GetTypeAlias<TValue>() #>.<#= resultValue #>;<#+
}
else
{#>
<#= resultType #> <#= targetVariable #> = <#= FormatValue<TValue>(resultValue) #>;<#+
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
<#= resultType #> <#= targetVariable #> = await context.ReadStateAsync<<#= resultType #>>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
<#= resultType #>? <#= targetVariable #> = await context.EvaluateValueAsync<<#= resultType #>>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
<#= resultType #> <#= targetVariable #> = await context.EvaluateValueAsync<<#= resultType #>>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,26 +0,0 @@
<#+
void EvaluateIntExpression(IntExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "int?" : "int";
if (expression is null)
{#>
<#= typeName #> <#= targetVariable #> = <#= isNullable ? "null" : "0" #>;<#+
}
else if (expression.IsLiteral)
{#>
<#= typeName #> <#= targetVariable #> = <#= expression.LiteralValue #>;<#+
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
<#= typeName #> <#= targetVariable #> = await context.ReadStateAsync<int>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
<#= typeName #>? <#= targetVariable #> = await context.EvaluateValueAsync<<#= typeName #>>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
<#= typeName #> <#= targetVariable #> = await context.EvaluateValueAsync<<#= typeName #>>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,26 +0,0 @@
<#+
void EvaluateListExpression<TElement>(ValueExpression expression, string targetVariable)
{
string typeName = GetTypeAlias<TElement>();
if (expression is null)
{#>
IList<<#= typeName #>>? <#= targetVariable #> = null;<#+
}
else if (expression.IsLiteral)
{#>
IList<<#= typeName #>>? <#= targetVariable #> = <#= FormatDataValue(expression.LiteralValue) #>;<#+
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
IList<<#= typeName #>>? <#= targetVariable #> = await context.ReadListAsync<<#= GetTypeAlias<TElement>() #>>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
IList<<#= typeName #>>? <#= targetVariable #>> = await context.EvaluateListAsync<<#= typeName #>>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
IList<<#= typeName #>>? <#= targetVariable #> = await context.EvaluateListAsync<<#= typeName #>>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,27 +0,0 @@
<#+
void EvaluateRecordExpression<TValue>(ObjectExpression<RecordDataValue> expression, string targetVariable)
{
string resultTypeName = $"Dictionary<string, {GetTypeAlias<TValue>()}?>?";
if (expression is null)
{#>
<#= resultTypeName #> <#= targetVariable #> = null;<#+
}
else if (expression.IsLiteral)
{#>
<#= resultTypeName #> <#= targetVariable #> =
<#= FormatDataValue(expression.LiteralValue) #>;<#+
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
<#= resultTypeName #> <#= targetVariable #> = await context.ReadStateAsync<<#= resultTypeName #>>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
<#= resultTypeName #>? <#= targetVariable #> = await context.EvaluateExpressionAsync<<#= resultTypeName #>>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
<#= resultTypeName #> <#= targetVariable #> = await context.EvaluateExpressionAsync<<#= resultTypeName #>>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,36 +0,0 @@
<#+
void EvaluateStringExpression(StringExpression expression, string targetVariable, bool isNullable = false)
{
string typeName = isNullable ? "string?" : "string";
if (expression is null)
{#>
<#= typeName #> <#= targetVariable #> = <#= isNullable ? "null" : "string.Empty" #>;<#+
}
else if (expression.IsLiteral)
{
if (expression.LiteralValue.Contains("\n"))
{#>
<#= typeName #> <#= targetVariable #> =
"""
<#= expression.LiteralValue #>
""";<#+
}
else
{#>
<#= typeName #> <#= targetVariable #> = <#= FormatStringValue(expression.LiteralValue) #>;<#+
}
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
<#= typeName #> <#= targetVariable #> = await context.ReadStateAsync<string>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
<#= typeName #> <#= targetVariable #> = await context.EvaluateValueAsync<string>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
<#= typeName #> <#= targetVariable #> = await context.EvaluateValueAsync<string>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,28 +0,0 @@
<#+
void EvaluateValueExpression(ValueExpression expression, string targetVariable) =>
EvaluateValueExpression<object>(expression, targetVariable);
void EvaluateValueExpression<TValue>(ValueExpression expression, string targetVariable)
{
if (expression is null)
{#>
<#= GetTypeAlias<TValue>() #>? <#= targetVariable #> = null;<#+
}
else if (expression.IsLiteral)
{#>
<#= GetTypeAlias<TValue>() #>? <#= targetVariable #> = <#= FormatDataValue(expression.LiteralValue) #>;<#+
}
else if (expression.IsVariableReference && expression.VariableReference.SegmentCount == 2)
{#>
<#= GetTypeAlias<TValue>() #>? <#= targetVariable #> = await context.ReadStateAsync<<#= GetTypeAlias<TValue>() #>>(key: "<#= expression.VariableReference.VariableName #>", scopeName: "<#= expression.VariableReference.NamespaceAlias #>").ConfigureAwait(false);<#+
}
else if (expression.IsVariableReference)
{#>
<#= GetTypeAlias<TValue>() #>? <#= targetVariable #> = await context.EvaluateValueAsync<<#= GetTypeAlias<TValue>() #>>(<#= FormatStringValue(expression.VariableReference.ToString()) #>).ConfigureAwait(false);<#+
}
else
{#>
<#= GetTypeAlias<TValue>() #>? <#= targetVariable #> = await context.EvaluateValueAsync<<#= GetTypeAlias<TValue>() #>>(<#= FormatStringValue(expression.ExpressionText) #>).ConfigureAwait(false);<#+
}
}
#>
@@ -1,25 +0,0 @@
<#+
void EvaluateMessageTemplate(TemplateLine templateLine, string variableName)
{
if (templateLine is not null)
{#>
string <#= variableName #> =
await context.FormatTemplateAsync(
"""<#+
FormatMessageTemplate(templateLine); #>
""");<#+
}
else
{#>
string? <#= variableName #> = null;<#+
}
}
void FormatMessageTemplate(TemplateLine line)
{
foreach (string text in line.ToTemplateString().ByLine())
{ #>
<#= text #><#+
}
}
#>
@@ -87,55 +87,6 @@ public static class DeclarativeWorkflowBuilder
return visitor.Complete();
}
/// <summary>
/// Generates source code (provider/executor scaffolding) for the workflow defined in the YAML file.
/// </summary>
/// <param name="workflowFile">The path to the workflow YAML file.</param>
/// <param name="workflowLanguage">The language to use for the generated code.</param>
/// <param name="workflowNamespace">Optional target namespace for the generated code.</param>
/// <param name="workflowPrefix">Optional prefix for generated workflow type.</param>
/// <returns>The generated source code representing the workflow.</returns>
public static string Eject(
string workflowFile,
DeclarativeWorkflowLanguage workflowLanguage,
string? workflowNamespace = null,
string? workflowPrefix = null)
{
using StreamReader yamlReader = File.OpenText(workflowFile);
return Eject(yamlReader, workflowLanguage, workflowNamespace, workflowPrefix);
}
/// <summary>
/// Generates source code (provider/executor scaffolding) for the workflow defined in the provided YAML reader.
/// </summary>
/// <param name="yamlReader">The reader supplying the workflow YAML.</param>
/// <param name="workflowLanguage">The language to use for the generated code.</param>
/// <param name="workflowNamespace">Optional target namespace for the generated code.</param>
/// <param name="workflowPrefix">Optional prefix for generated workflow type.</param>
/// <returns>The generated source code representing the workflow.</returns>
public static string Eject(
TextReader yamlReader,
DeclarativeWorkflowLanguage workflowLanguage,
string? workflowNamespace = null,
string? workflowPrefix = null)
{
if (workflowLanguage != DeclarativeWorkflowLanguage.CSharp)
{
throw new NotSupportedException($"Converting workflow to {workflowLanguage} is not currently supported.");
}
AdaptiveDialog workflowElement = ReadWorkflow(yamlReader);
string rootId = WorkflowActionVisitor.Steps.Root(workflowElement);
WorkflowTypeInfo typeInfo = workflowElement.WrapWithBot().Describe();
WorkflowTemplateVisitor visitor = new(rootId, typeInfo);
WorkflowElementWalker walker = new(visitor);
walker.Visit(workflowElement);
return visitor.Complete(workflowNamespace, workflowPrefix);
}
private static AdaptiveDialog ReadWorkflow(TextReader yamlReader)
{
BotElement rootElement = YamlSerializer.Deserialize<BotElement>(yamlReader) ?? throw new DeclarativeModelException("Workflow undefined.");
@@ -1,24 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Agents.AI.Workflows.Declarative;
/// <summary>
/// Defines programming language for workflow ejection.
/// </summary>
public enum DeclarativeWorkflowLanguage
{
/// <summary>
/// Python programming language.
/// </summary>
Python,
/// <summary>
/// C# programming language.
/// </summary>
CSharp,
/// <summary>
/// JavaScript programming language.
/// </summary>
JavaScript,
}
@@ -1,75 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
namespace Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
internal sealed class WorkflowCodeBuilder : IModelBuilder<string>
{
private readonly HashSet<string> _actions;
private readonly List<string> _definitions;
private readonly List<string> _instances;
private readonly List<string> _edges;
private readonly string _rootId;
public WorkflowCodeBuilder(string rootId)
{
this._actions = [];
this._definitions = [];
this._instances = [];
this._edges = [];
this._rootId = rootId;
}
public string GenerateCode(string? workflowNamespace, string? workflowPrefix)
{
ProviderTemplate template =
new(this._rootId, this._definitions, this._instances, this._edges)
{
Namespace = workflowNamespace,
Prefix = workflowPrefix,
};
return template.TransformText().Trim();
}
public void Connect(IModeledAction source, IModeledAction target, string? condition)
{
Debug.WriteLine($"> CONNECT: {source.Id} => {target.Id}{(condition is null ? string.Empty : " (?)")}");
this.HandelAction(source);
this.HandelAction(target);
this._edges.Add(new EdgeTemplate(source.Id, target.Id, condition).TransformText());
}
private void HandelAction(IModeledAction action)
{
// All templates are based on "CodeTemplate"
if (action is not CodeTemplate template)
{
// Something has gone very wrong.
throw new DeclarativeModelException($"Unable to generate code for: {action.GetType().Name}.");
}
if (this._actions.Add(action.Id))
{
switch (action)
{
case EmptyTemplate:
case DefaultTemplate:
this._instances.Add(template.TransformText());
break;
case ActionTemplate actionTemplate:
this._definitions.Add(template.TransformText());
this._instances.Add(new InstanceTemplate(action.Id, this._rootId, actionTemplate.UseAgentProvider).TransformText());
break;
case RootTemplate:
this._definitions.Add(template.TransformText());
break;
}
}
}
}
@@ -1,500 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel;
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
internal sealed class WorkflowTemplateVisitor : DialogActionVisitor
{
private readonly string _rootId;
private readonly WorkflowModel<string> _workflowModel;
public WorkflowTemplateVisitor(
string workflowId,
WorkflowTypeInfo typeInfo)
{
this._rootId = workflowId;
this._workflowModel = new WorkflowModel<string>(new RootTemplate(workflowId, typeInfo));
WorkflowDiagnostics.SetFoundryProduct();
}
public bool HasUnsupportedActions { get; private set; }
public string Complete(string? workflowNamespace = null, string? workflowPrefix = null)
{
WorkflowCodeBuilder builder = new(this._rootId);
this._workflowModel.Build(builder);
return builder.GenerateCode(workflowNamespace, workflowPrefix);
}
protected override void Visit(ActionScope item)
{
this.Trace(item);
string parentId = GetParentId(item);
// Handle case where root element is its own parent
if (item.Id.Equals(parentId))
{
parentId = WorkflowActionVisitor.Steps.Root(parentId);
}
this.ContinueWith(new EmptyTemplate(item.Id.Value, this._rootId), parentId, condition: null, CompletionHandler);
//// Complete the action scope.
void CompletionHandler()
{
// No completion for root scope
if (this._workflowModel.GetDepth(item.Id.Value) > 1)
{
// Define post action for this scope
string completionId = this.ContinuationFor(item.Id.Value);
this._workflowModel.AddLinkFromPeer(item.Id.Value, completionId);
// Transition to post action of parent scope
this._workflowModel.AddLink(completionId, WorkflowActionVisitor.Steps.Post(parentId));
}
}
}
public override void VisitConditionItem(ConditionItem item)
{
this.Trace(item);
string parentId = GetParentId(item);
ConditionGroupTemplate? conditionGroup = this._workflowModel.LocateParent<ConditionGroupTemplate>(parentId);
if (conditionGroup is not null)
{
string stepId = ConditionGroupExecutor.Steps.Item(conditionGroup.Model, item);
this._workflowModel.AddNode(new EmptyTemplate(stepId, this._rootId), parentId, CompletionHandler);
base.VisitConditionItem(item);
// Complete the condition item.
void CompletionHandler()
{
string completionId = this.ContinuationFor(stepId);
this._workflowModel.AddLink(completionId, WorkflowActionVisitor.Steps.Post(conditionGroup.Id));
// Merge link when no action group is defined
if (!item.Actions.Any())
{
this._workflowModel.AddLink(stepId, completionId);
}
}
}
}
protected override void Visit(ConditionGroup item)
{
this.Trace(item);
ConditionGroupTemplate action = new(item);
this.ContinueWith(action);
this.ContinuationFor(action.Id, parentId: action.ParentId);
string? lastConditionItemId = null;
foreach (ConditionItem conditionItem in item.Conditions)
{
// Create conditional link for conditional action
lastConditionItemId = ConditionGroupExecutor.Steps.Item(item, conditionItem);
this._workflowModel.AddLink(action.Id, lastConditionItemId, $@"ActionExecutor.IsMatch(""{lastConditionItemId}"", result)");
conditionItem.Accept(this);
}
if (item.ElseActions?.Actions.Length > 0)
{
if (lastConditionItemId is not null)
{
// Create clean start for else action from prior conditions
this.RestartAfter(lastConditionItemId, action.Id);
}
// Create conditional link for else action
string stepId = ConditionGroupExecutor.Steps.Else(item);
this._workflowModel.AddLink(action.Id, stepId, $@"ActionExecutor.IsMatch(""{stepId}"", result)");
}
}
protected override void Visit(GotoAction item)
{
this.Trace(item);
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Transition to target action
this._workflowModel.AddLink(action.Id, item.ActionId.Value);
// Define a clean-start to ensure "goto" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
protected override void Visit(Foreach item)
{
this.Trace(item);
// Entry point for loop
ForeachTemplate action = new(item);
string loopId = ForeachExecutor.Steps.Next(action.Id);
this.ContinueWith(action, condition: null, CompletionHandler); // Foreach
// Transition to select the next item
this.ContinueWith(new EmptyTemplate(loopId, this._rootId, $"{action.Id.FormatName()}.{nameof(ForeachExecutor.TakeNextAsync)}"), action.Id);
// Transition to post action if no more items
string continuationId = this.ContinuationFor(action.Id, parentId: action.ParentId); // Action continuation
this._workflowModel.AddLink(loopId, continuationId, $"!{action.Id.FormatName()}.{nameof(ForeachExecutor.HasValue)}");
// Transition to start of inner actions if there is a current item
string startId = ForeachExecutor.Steps.Start(action.Id);
this._workflowModel.AddNode(new EmptyTemplate(startId, this._rootId), action.Id);
this._workflowModel.AddLink(loopId, startId, $"{action.Id.FormatName()}.{nameof(ForeachExecutor.HasValue)}");
void CompletionHandler()
{
// Transition to end of inner actions
string endActionsId = ForeachExecutor.Steps.End(action.Id); // Loop continuation
this.ContinueWith(new EmptyTemplate(endActionsId, this._rootId, $"{action.Id.FormatName()}.{nameof(ForeachExecutor.CompleteAsync)}"), action.Id);
// Transition to select the next item
this._workflowModel.AddLink(endActionsId, loopId);
}
}
protected override void Visit(BreakLoop item)
{
this.Trace(item);
// Locate the nearest "Foreach" loop that contains this action
ForeachTemplate? loopAction = this._workflowModel.LocateParent<ForeachTemplate>(item.GetParentId());
// Skip action if its not contained a loop
if (loopAction is not null)
{
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Transition to post action
this._workflowModel.AddLink(action.Id, WorkflowActionVisitor.Steps.Post(loopAction.Id));
// Define a clean-start to ensure "break" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
}
protected override void Visit(ContinueLoop item)
{
this.Trace(item);
// Locate the nearest "Foreach" loop that contains this action
ForeachTemplate? loopAction = this._workflowModel.LocateParent<ForeachTemplate>(item.GetParentId());
// Skip action if its not contained a loop
if (loopAction is not null)
{
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Transition to select the next item
this._workflowModel.AddLink(action.Id, ForeachExecutor.Steps.Start(loopAction.Id));
// Define a clean-start to ensure "continue" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
}
protected override void Visit(Question item)
{
this.NotSupported(item);
}
protected override void Visit(RequestExternalInput item)
{
this.NotSupported(item);
}
protected override void Visit(EndDialog item)
{
this.Trace(item);
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Define a clean-start to ensure "end" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
protected override void Visit(EndConversation item)
{
this.Trace(item);
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Define a clean-start to ensure "end" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
protected override void Visit(CancelAllDialogs item)
{
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Define a clean-start to ensure "end" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
protected override void Visit(CancelDialog item)
{
// Represent action with default executor
DefaultTemplate action = new(item, this._rootId);
this.ContinueWith(action);
// Define a clean-start to ensure "end" is not a source for any edge
this.RestartAfter(action.Id, action.ParentId);
}
protected override void Visit(CreateConversation item)
{
this.Trace(item);
this.ContinueWith(new CreateConversationTemplate(item));
}
protected override void Visit(AddConversationMessage item)
{
this.Trace(item);
this.ContinueWith(new AddConversationMessageTemplate(item));
}
protected override void Visit(CopyConversationMessages item)
{
this.Trace(item);
this.ContinueWith(new CopyConversationMessagesTemplate(item));
}
protected override void Visit(InvokeAzureAgent item)
{
this.Trace(item);
this.ContinueWith(new InvokeAzureAgentTemplate(item));
}
protected override void Visit(InvokeAzureResponse item)
{
this.NotSupported(item);
}
protected override void Visit(RetrieveConversationMessage item)
{
this.Trace(item);
this.ContinueWith(new RetrieveConversationMessageTemplate(item));
}
protected override void Visit(RetrieveConversationMessages item)
{
this.Trace(item);
this.ContinueWith(new RetrieveConversationMessagesTemplate(item));
}
protected override void Visit(SetVariable item)
{
this.Trace(item);
this.ContinueWith(new SetVariableTemplate(item));
}
protected override void Visit(SetMultipleVariables item)
{
this.Trace(item);
this.ContinueWith(new SetMultipleVariablesTemplate(item));
}
protected override void Visit(SetTextVariable item)
{
this.Trace(item);
this.ContinueWith(new SetTextVariableTemplate(item));
}
protected override void Visit(ClearAllVariables item)
{
this.Trace(item);
this.ContinueWith(new ClearAllVariablesTemplate(item));
}
protected override void Visit(ResetVariable item)
{
this.Trace(item);
this.ContinueWith(new ResetVariableTemplate(item));
}
protected override void Visit(EditTable item)
{
this.NotSupported(item);
}
protected override void Visit(EditTableV2 item)
{
this.NotSupported(item);
}
protected override void Visit(ParseValue item)
{
this.Trace(item);
this.ContinueWith(new ParseValueTemplate(item));
}
protected override void Visit(SendActivity item)
{
this.Trace(item);
this.ContinueWith(new SendActivityTemplate(item));
}
#region Not supported
protected override void Visit(InvokeMcpTool item) => this.NotSupported(item);
protected override void Visit(InvokeFunctionTool item) => this.NotSupported(item);
protected override void Visit(AnswerQuestionWithAI item) => this.NotSupported(item);
protected override void Visit(DeleteActivity item) => this.NotSupported(item);
protected override void Visit(GetActivityMembers item) => this.NotSupported(item);
protected override void Visit(UpdateActivity item) => this.NotSupported(item);
protected override void Visit(ActivateExternalTrigger item) => this.NotSupported(item);
protected override void Visit(DisableTrigger item) => this.NotSupported(item);
protected override void Visit(WaitForConnectorTrigger item) => this.NotSupported(item);
protected override void Visit(InvokeConnectorAction item) => this.NotSupported(item);
protected override void Visit(InvokeCustomModelAction item) => this.NotSupported(item);
protected override void Visit(InvokeFlowAction item) => this.NotSupported(item);
protected override void Visit(InvokeAIBuilderModelAction item) => this.NotSupported(item);
protected override void Visit(InvokeSkillAction item) => this.NotSupported(item);
protected override void Visit(AdaptiveCardPrompt item) => this.NotSupported(item);
protected override void Visit(CSATQuestion item) => this.NotSupported(item);
protected override void Visit(OAuthInput item) => this.NotSupported(item);
protected override void Visit(BeginDialog item) => this.NotSupported(item);
protected override void Visit(UnknownDialogAction item) => this.NotSupported(item);
protected override void Visit(RepeatDialog item) => this.NotSupported(item);
protected override void Visit(ReplaceDialog item) => this.NotSupported(item);
protected override void Visit(EmitEvent item) => this.NotSupported(item);
protected override void Visit(GetConversationMembers item) => this.NotSupported(item);
protected override void Visit(HttpRequestAction item) => this.NotSupported(item);
protected override void Visit(RecognizeIntent item) => this.NotSupported(item);
protected override void Visit(TransferConversation item) => this.NotSupported(item);
protected override void Visit(TransferConversationV2 item) => this.NotSupported(item);
protected override void Visit(SignOutUser item) => this.NotSupported(item);
protected override void Visit(LogCustomTelemetryEvent item) => this.NotSupported(item);
protected override void Visit(DisconnectedNodeContainer item) => this.NotSupported(item);
protected override void Visit(CreateSearchQuery item) => this.NotSupported(item);
protected override void Visit(SearchKnowledgeSources item) => this.NotSupported(item);
protected override void Visit(SearchAndSummarizeWithCustomModel item) => this.NotSupported(item);
protected override void Visit(SearchAndSummarizeContent item) => this.NotSupported(item);
#endregion
private void ContinueWith(
ActionTemplate action,
string? condition = null,
Action? completionHandler = null)
{
this.ContinueWith(action, action.ParentId, condition, completionHandler);
}
private void ContinueWith(
IModeledAction action,
string parentId,
string? condition = null,
Action? completionHandler = null)
{
this._workflowModel.AddNode(action, parentId, completionHandler);
this._workflowModel.AddLinkFromPeer(parentId, action.Id, condition);
}
private string ContinuationFor(string parentId, string? stepAction = null) => this.ContinuationFor(parentId, parentId, stepAction);
private string ContinuationFor(string actionId, string parentId, string? stepAction = null)
{
actionId = WorkflowActionVisitor.Steps.Post(actionId);
this._workflowModel.AddNode(new EmptyTemplate(actionId, this._rootId, stepAction), parentId);
return actionId;
}
private void RestartAfter(string actionId, string parentId) =>
this._workflowModel.AddNode(new EmptyTemplate(WorkflowActionVisitor.Steps.Restart(actionId), this._rootId), parentId);
private static string GetParentId(BotElement item) =>
item.GetParentId() ??
throw new DeclarativeModelException($"Missing parent ID for action element: {item.GetId()} [{item.GetType().Name}].");
private void NotSupported(DialogAction item)
{
Debug.WriteLine($"> UNKNOWN: {FormatItem(item)} => {FormatParent(item)}");
this.HasUnsupportedActions = true;
}
private void Trace(BotElement item) =>
Debug.WriteLine($"> VISIT: {new string('\t', this._workflowModel.GetDepth(item.GetParentId()))}{FormatItem(item)} => {FormatParent(item)}");
private void Trace(DialogAction item)
{
string? parentId = item.GetParentId();
if (item.Id.Equals(parentId ?? string.Empty))
{
parentId = WorkflowActionVisitor.Steps.Root(parentId);
}
Debug.WriteLine($"> VISIT: {new string('\t', this._workflowModel.GetDepth(parentId))}{FormatItem(item)} => {FormatParent(item)}");
}
private static string FormatItem(BotElement element) => $"{element.GetType().Name} ({element.GetId()})";
private static string FormatParent(BotElement element) =>
element.Parent is null ?
throw new DeclarativeModelException($"Undefined parent for {element.GetType().Name} that is member of {element.GetId()}.") :
$"{element.Parent.GetType().Name} ({element.GetParentId()})";
}
@@ -38,18 +38,6 @@
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<None Update="CodeGen\*Template.tt">
<Generator>TextTemplatingFilePreprocessor</Generator>
<LastGenOutput>%(Filename).cs</LastGenOutput>
</None>
<Compile Update="CodeGen\*Template.cs">
<DependentUpon>%(Filename).tt</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Microsoft.Agents.AI.Workflows.Declarative.UnitTests" />
<InternalsVisibleTo Include="Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests" />
-73
View File
@@ -1,73 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
#if !NET
using System.Threading.Tasks;
#endif
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.Extensions.AI;
using Xunit.Sdk;
namespace Shared.Code;
internal static class Compiler
{
public static IEnumerable<Assembly> RepoDependencies(params IEnumerable<Type> types)
{
yield return typeof(object).Assembly;
yield return typeof(Console).Assembly;
yield return typeof(Enumerable).Assembly;
#if NET
yield return Assembly.Load("System.Runtime");
#else
yield return Assembly.LoadFrom(AppDomain.CurrentDomain.GetAssemblies().Single(a => a.GetName().Name == "netstandard").Location);
yield return typeof(IAsyncEnumerable<>).Assembly;
yield return typeof(ValueTask).Assembly;
#endif
yield return typeof(ChatMessage).Assembly;
yield return typeof(AIAgent).Assembly;
yield return typeof(Workflow).Assembly;
foreach (Type type in types)
{
yield return type.Assembly;
}
}
public static Assembly Build(string workflowProviderCode, params IEnumerable<Assembly> dependencies)
{
// Compile the code
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(workflowProviderCode);
CSharpCompilation compilation = CSharpCompilation.Create(
"DynamicAssembly",
[syntaxTree],
dependencies.Select(d => MetadataReference.CreateFromFile(d.Location)),
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
using MemoryStream memoryStream = new();
EmitResult result = compilation.Emit(memoryStream);
if (!result.Success)
{
Console.WriteLine("COMPLILATION FAILURE:");
foreach (var diagnostic in result.Diagnostics)
{
Console.WriteLine(diagnostic.ToString());
}
throw new XunitException("Compilation failed.");
}
Console.WriteLine("COMPLILATION SUCCEEDED...");
memoryStream.Seek(0, SeekOrigin.Begin);
return Assembly.Load(memoryStream.ToArray());
}
}
-11
View File
@@ -1,11 +0,0 @@
# Build Code
Re-usable utility for building C# code in tests.
To use this in your project, add the following to your `.csproj` file:
```xml
<PropertyGroup>
<InjectSharedBuildTestCode>true</InjectSharedBuildTestCode>
</PropertyGroup>
```