.NET Workflows - Fix code generation cases (#1242)

* Updated

* Passing

* Ready

* Update dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Workflows/ConversationMessages.yaml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Comment

* Code analysis

* Unit-tests/provider signature

* Comment

* Consistent

* Checkpoint

* Fixed

* Revert

* Test display name

* Enable tests

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Chris
2025-10-06 23:34:46 +00:00
committed by GitHub
co-authored by Copilot
parent 477c0dbf1a
commit 0113e0466d
19 changed files with 616 additions and 24 deletions
@@ -60,8 +60,8 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
"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 await agentProvider.CreateMessageAsync(conver" +
"sationId, newMessage, cancellationToken).ConfigureAwait(false);");
"es = this.GetMetadata() };\n newMessage = await agentProvider.CreateMessag" +
"eAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);");
AssignVariable(this.Message, "newMessage");
@@ -17,7 +17,7 @@ internal sealed class <#= this.Name #>Executor(FormulaSession session, WorkflowA
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() };
await agentProvider.CreateMessageAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);<#
newMessage = await agentProvider.CreateMessageAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);<#
AssignVariable(this.Message, "newMessage");
#>
return default;
@@ -1,7 +1,7 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version: 18.0.0.0
// Runtime Version: 17.0.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -19,7 +19,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
/// <summary>
/// Class to produce the template output
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")]
internal partial class RetrieveConversationMessagesTemplate : ActionTemplate
{
/// <summary>
@@ -44,8 +44,8 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
this.Write("\n");
this.Write("\n");
this.Write("\n");
this.Write("f\n/// <summary>\n/// Retrieves a specific message from an agent conversation.\n/// " +
"</summary>\ninternal sealed class ");
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, WorkflowAgentProvider agentProvider) : ActionExe" +
"cutor(id: \"");
@@ -60,14 +60,19 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.CodeGen
EvaluateStringExpression(this.Model.MessageBefore, "before", isNullable: true);
EvaluateEnumExpression<AgentMessageSortOrderWrapper, bool>(this.Model.SortOrder, "newestFirst", SortMap, defaultValue: DefaultSort);
this.Write(@"
ChatMessage messages =
await agentProvider.GetMessageAsync(
converationId,
IAsyncEnumerable<ChatMessage> messagesResult =
agentProvider.GetMessagesAsync(
conversationId,
limit,
after,
before,
newestFirst,
cancellationToken).ConfigureAwait(false);");
cancellationToken);
List<ChatMessage> messages = [];
await foreach (ChatMessage message in messagesResult.ConfigureAwait(false))
{
messages.Add(message);
}");
AssignVariable(this.Model.Messages, "messages");
@@ -1,7 +1,7 @@
<#@ template language="C#" inherits="ActionTemplate" visibility="internal" linePragmas="false" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ include file="Snippets/Index.tt" once="true" #>f
<#@ include file="Snippets/Index.tt" once="true" #>
/// <summary>
/// Retrieves a specific message from an agent conversation.
/// </summary>
@@ -15,14 +15,19 @@ internal sealed class <#= this.Name #>Executor(FormulaSession session, WorkflowA
EvaluateStringExpression(this.Model.MessageAfter, "after", isNullable: true);
EvaluateStringExpression(this.Model.MessageBefore, "before", isNullable: true);
EvaluateEnumExpression<AgentMessageSortOrderWrapper, bool>(this.Model.SortOrder, "newestFirst", SortMap, defaultValue: DefaultSort); #>
ChatMessage messages =
await agentProvider.GetMessageAsync(
converationId,
IAsyncEnumerable<ChatMessage> messagesResult =
agentProvider.GetMessagesAsync(
conversationId,
limit,
after,
before,
newestFirst,
cancellationToken).ConfigureAwait(false);<#
cancellationToken);
List<ChatMessage> messages = [];
await foreach (ChatMessage message in messagesResult.ConfigureAwait(false))
{
messages.Add(message);
}<#
AssignVariable(this.Model.Messages, "messages");
#>
return default;
@@ -19,8 +19,8 @@ public sealed class DeclarativeCodeGenTest(ITestOutputHelper output) : WorkflowT
[InlineData("SendActivity.yaml", "SendActivity.json")]
[InlineData("InvokeAgent.yaml", "InvokeAgent.json")]
[InlineData("InvokeAgent.yaml", "InvokeAgent.json", true)]
[InlineData("ConversationMessages.yaml", "ConversationMessages.json", Skip = "Issue #1236")]
[InlineData("ConversationMessages.yaml", "ConversationMessages.json", true, Skip = "Issue #1236")]
[InlineData("ConversationMessages.yaml", "ConversationMessages.json")]
[InlineData("ConversationMessages.yaml", "ConversationMessages.json", true)]
public Task ValidateCaseAsync(string workflowFileName, string testcaseFileName, bool externalConveration = false) =>
this.RunWorkflowAsync(Path.Combine(Environment.CurrentDirectory, "Workflows", workflowFileName), testcaseFileName, externalConveration);
@@ -10,15 +10,25 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class CopyConversationMessagesTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void CopyConversationMessages()
public void CopyConversationMessagesLiteral()
{
// Act, Assert
this.ExecuteTest(
nameof(CopyConversationMessages),
nameof(CopyConversationMessagesLiteral),
StringExpression.Literal("#conv_dm99"),
ValueExpression.Variable(PropertyPath.TopicVariable("MyMessages")));
}
[Fact]
public void CopyConversationMessagesVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(CopyConversationMessagesVariable),
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
ValueExpression.Variable(PropertyPath.TopicVariable("MyMessages")));
}
private void ExecuteTest(
string displayName,
StringExpression conversation,
@@ -14,9 +14,12 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public sealed class DeclarativeEjectionTest(ITestOutputHelper output) : WorkflowTest(output)
{
[Theory]
[InlineData("AddConversationMessage.yaml")]
[InlineData("ClearAllVariables.yaml")]
[InlineData("CopyConversationMessages.yaml")]
[InlineData("Condition.yaml")]
[InlineData("ConditionElse.yaml")]
[InlineData("CreateConversation.yaml")]
[InlineData("EditTable.yaml")]
[InlineData("EditTableV2.yaml")]
[InlineData("EndConversation.yaml")]
@@ -28,6 +31,8 @@ public sealed class DeclarativeEjectionTest(ITestOutputHelper output) : Workflow
[InlineData("LoopEach.yaml")]
[InlineData("ParseValue.yaml")]
[InlineData("ResetVariable.yaml")]
[InlineData("RetrieveConversationMessage.yaml")]
[InlineData("RetrieveConversationMessages.yaml")]
[InlineData("SendActivity.yaml")]
[InlineData("SetVariable.yaml")]
[InlineData("SetTextVariable.yaml")]
@@ -10,14 +10,24 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class RetrieveConversationMessageTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void RetrieveMessageLiteral()
public void RetrieveConversationVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(RetrieveMessageLiteral),
nameof(RetrieveConversationVariable),
"TestVariable",
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
StringExpression.Literal("#mid_43"));
}
[Fact]
public void RetrieveMessageVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(RetrieveMessageVariable),
"TestVariable",
StringExpression.Literal("#cid_3"),
StringExpression.Literal("#mid_43"));
StringExpression.Variable(PropertyPath.TopicVariable("TestMessage")));
}
private void ExecuteTest(
@@ -16,7 +16,7 @@ public class RetrieveConversationMessagesTemplateTest(ITestOutputHelper output)
this.ExecuteTest(
nameof(DefaultQuery),
"TestVariable",
StringExpression.Literal("#cid_3"));
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")));
}
[Fact]
@@ -0,0 +1,119 @@
// ------------------------------------------------------------------------------
// <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;
namespace Test.WorkflowProviders;
/// <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 WorkflowProvider
{
/// <summary>
/// The root executor for a declarative workflow.
/// </summary>
internal sealed class WorkflowTestRootExecutor<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage> inputTransform) :
RootExecutor<TInput>("workflow_test_Root", options, inputTransform)
where TInput : notnull
{
protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
{
// Initialize variables
await context.QueueStateUpdateAsync("MyMessage1", UnassignedValue.Instance, "Local").ConfigureAwait(false);
await context.QueueStateUpdateAsync("TestInput", UnassignedValue.Instance, "Local").ConfigureAwait(false);
}
}
/// <summary>
/// Adds a new message to the specified agent conversation
/// </summary>
internal sealed class AddMessageExecutor(FormulaSession session, WorkflowAgentProvider agentProvider) : ActionExecutor(id: "add_message", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string? conversationId = await context.ReadStateAsync<string>(key: "ConversationId", scopeName: "System").ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(conversationId))
{
throw new DeclarativeActionException($"Conversation identifier must be defined: {this.Id}");
}
ChatMessage newMessage = new(ChatRole.User, await this.GetContentAsync(context).ConfigureAwait(false)) { AdditionalProperties = this.GetMetadata() };
newMessage = await agentProvider.CreateMessageAsync(conversationId, newMessage, cancellationToken).ConfigureAwait(false);
await context.QueueStateUpdateAsync(key: "MyMessage1", value: newMessage, scopeName: "Local").ConfigureAwait(false);
return default;
}
private async ValueTask<IList<AIContent>> GetContentAsync(IWorkflowContext context)
{
List<AIContent> content = [];
string contentValue1 =
await context.FormatTemplateAsync(
"""
{Local.TestInput}
""");
content.Add(new TextContent(contentValue1));
return content;
}
private AdditionalPropertiesDictionary? GetMetadata()
{
Dictionary<string, object?>? metadata = null;
if (metadata is null)
{
return null;
}
return new AdditionalPropertiesDictionary(metadata);
}
}
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);
WorkflowTestRootExecutor<TInput> workflowTestRoot = new(options, inputTransform);
DelegateExecutor workflowTest = new(id: "workflow_test", workflowTestRoot.Session);
AddMessageExecutor addMessage = new(workflowTestRoot.Session, options.AgentProvider);
// Define the workflow builder
WorkflowBuilder builder = new(workflowTestRoot);
// Connect executors
builder.AddEdge(workflowTestRoot, workflowTest);
builder.AddEdge(workflowTest, addMessage);
// Build the workflow
return builder.Build();
}
}
@@ -0,0 +1,15 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_test
actions:
- kind: AddConversationMessage
id: add_message
message: Local.MyMessage1
role: User
conversationId: =System.ConversationId
content:
- type: Text
value: {Local.TestInput}
@@ -0,0 +1,95 @@
// ------------------------------------------------------------------------------
// <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;
namespace Test.WorkflowProviders;
/// <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 WorkflowProvider
{
/// <summary>
/// The root executor for a declarative workflow.
/// </summary>
internal sealed class WorkflowTestRootExecutor<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage> inputTransform) :
RootExecutor<TInput>("workflow_test_Root", options, inputTransform)
where TInput : notnull
{
protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
{
}
}
/// <summary>
/// Copies one or more messages into the specified agent conversation.
/// </summary>
internal sealed class CopyMessagesExecutor(FormulaSession session, WorkflowAgentProvider agentProvider) : ActionExecutor(id: "copy_messages", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string? conversationId = await context.ReadStateAsync<string>(key: "ConversationId", scopeName: "System").ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(conversationId))
{
throw new DeclarativeActionException($"Conversation identifier must be defined: {this.Id}");
}
ChatMessage[]? messages = await context.EvaluateValueAsync<ChatMessage[]>("""[UserMessage("Hello, how can I assist you today?")]""").ConfigureAwait(false);
if (messages is not null)
{
foreach (ChatMessage message in messages)
{
await agentProvider.CreateMessageAsync(conversationId, message, cancellationToken).ConfigureAwait(false);
}
}
return default;
}
}
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);
WorkflowTestRootExecutor<TInput> workflowTestRoot = new(options, inputTransform);
DelegateExecutor workflowTest = new(id: "workflow_test", workflowTestRoot.Session);
CopyMessagesExecutor copyMessages = new(workflowTestRoot.Session, options.AgentProvider);
// Define the workflow builder
WorkflowBuilder builder = new(workflowTestRoot);
// Connect executors
builder.AddEdge(workflowTestRoot, workflowTest);
builder.AddEdge(workflowTest, copyMessages);
// Build the workflow
return builder.Build();
}
}
@@ -0,0 +1,12 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_test
actions:
- kind: CopyConversationMessages
id: copy_messages
conversationId: =System.ConversationId
messages: =[UserMessage("Hello, how can I assist you today?")]
@@ -0,0 +1,88 @@
// ------------------------------------------------------------------------------
// <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;
namespace Test.WorkflowProviders;
/// <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 WorkflowProvider
{
/// <summary>
/// The root executor for a declarative workflow.
/// </summary>
internal sealed class WorkflowTestRootExecutor<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage> inputTransform) :
RootExecutor<TInput>("workflow_test_Root", options, inputTransform)
where TInput : notnull
{
protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
{
// Initialize variables
await context.QueueStateUpdateAsync("PrivateConversationId", UnassignedValue.Instance, "Local").ConfigureAwait(false);
}
}
/// <summary>
/// Creates a new conversation and stores the identifier value to the "Local.PrivateConversationId" variable.
/// </summary>
internal sealed class ConversationCreateExecutor(FormulaSession session, WorkflowAgentProvider agentProvider) : ActionExecutor(id: "conversation_create", session)
{
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string conversationId = await agentProvider.CreateConversationAsync(cancellationToken).ConfigureAwait(false);
await context.QueueStateUpdateAsync(key: "PrivateConversationId", value: conversationId, scopeName: "Local").ConfigureAwait(false);
await context.AddEventAsync(new ConversationUpdateEvent(conversationId)).ConfigureAwait(false);
return default;
}
}
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);
WorkflowTestRootExecutor<TInput> workflowTestRoot = new(options, inputTransform);
DelegateExecutor workflowTest = new(id: "workflow_test", workflowTestRoot.Session);
ConversationCreateExecutor conversationCreate = new(workflowTestRoot.Session, options.AgentProvider);
// Define the workflow builder
WorkflowBuilder builder = new(workflowTestRoot);
// Connect executors
builder.AddEdge(workflowTestRoot, workflowTest);
builder.AddEdge(workflowTest, conversationCreate);
// Build the workflow
return builder.Build();
}
}
@@ -0,0 +1,10 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_test
actions:
- kind: CreateConversation
id: conversation_create
conversationId: Local.PrivateConversationId
@@ -0,0 +1,91 @@
// ------------------------------------------------------------------------------
// <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;
namespace Test.WorkflowProviders;
/// <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 WorkflowProvider
{
/// <summary>
/// The root executor for a declarative workflow.
/// </summary>
internal sealed class WorkflowTestRootExecutor<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage> inputTransform) :
RootExecutor<TInput>("workflow_test_Root", options, inputTransform)
where TInput : notnull
{
protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
{
// Initialize variables
await context.QueueStateUpdateAsync("MyMessage1Copy", UnassignedValue.Instance, "Local").ConfigureAwait(false);
await context.QueueStateUpdateAsync("MyMessageId", UnassignedValue.Instance, "Local").ConfigureAwait(false);
await context.QueueStateUpdateAsync("PrivateConversationId", UnassignedValue.Instance, "Local").ConfigureAwait(false);
}
}
/// <summary>
/// Retrieves a list of messages from an agent conversation.
/// </summary>
internal sealed class GetMessageSingleExecutor(FormulaSession session, WorkflowAgentProvider agentProvider) : ActionExecutor(id: "get_message_single", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string conversationId = await context.ReadStateAsync<string>(key: "PrivateConversationId", scopeName: "Local").ConfigureAwait(false);
string messageId = await context.ReadStateAsync<string>(key: "MyMessageId", scopeName: "Local").ConfigureAwait(false);
ChatMessage message = await agentProvider.GetMessageAsync(conversationId, messageId, cancellationToken).ConfigureAwait(false);
await context.QueueStateUpdateAsync(key: "MyMessage1Copy", value: message, scopeName: "Local").ConfigureAwait(false);
return default;
}
}
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);
WorkflowTestRootExecutor<TInput> workflowTestRoot = new(options, inputTransform);
DelegateExecutor workflowTest = new(id: "workflow_test", workflowTestRoot.Session);
GetMessageSingleExecutor getMessageSingle = new(workflowTestRoot.Session, options.AgentProvider);
// Define the workflow builder
WorkflowBuilder builder = new(workflowTestRoot);
// Connect executors
builder.AddEdge(workflowTestRoot, workflowTest);
builder.AddEdge(workflowTest, getMessageSingle);
// Build the workflow
return builder.Build();
}
}
@@ -0,0 +1,12 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_test
actions:
- kind: RetrieveConversationMessage
id: get_message_single
message: Local.MyMessage1Copy
conversationId: =Local.PrivateConversationId
messageId: =Local.MyMessageId
@@ -0,0 +1,104 @@
// ------------------------------------------------------------------------------
// <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;
namespace Test.WorkflowProviders;
/// <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 WorkflowProvider
{
/// <summary>
/// The root executor for a declarative workflow.
/// </summary>
internal sealed class WorkflowTestRootExecutor<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage> inputTransform) :
RootExecutor<TInput>("workflow_test_Root", options, inputTransform)
where TInput : notnull
{
protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
{
// Initialize variables
await context.QueueStateUpdateAsync("AllMessages", UnassignedValue.Instance, "Local").ConfigureAwait(false);
}
}
/// <summary>
/// Retrieves a specific message from an agent conversation.
/// </summary>
internal sealed class GetMessagesAllExecutor(FormulaSession session, WorkflowAgentProvider agentProvider) : ActionExecutor(id: "get_messages_all", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string conversationId = await context.ReadStateAsync<string>(key: "ConversationId", scopeName: "System").ConfigureAwait(false);
int limit = 20;
string? after = null;
string? before = null;
bool newestFirst = false;
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);
}
await context.QueueStateUpdateAsync(key: "AllMessages", value: messages, scopeName: "Local").ConfigureAwait(false);
return default;
}
}
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);
WorkflowTestRootExecutor<TInput> workflowTestRoot = new(options, inputTransform);
DelegateExecutor workflowTest = new(id: "workflow_test", workflowTestRoot.Session);
GetMessagesAllExecutor getMessagesAll = new(workflowTestRoot.Session, options.AgentProvider);
// Define the workflow builder
WorkflowBuilder builder = new(workflowTestRoot);
// Connect executors
builder.AddEdge(workflowTestRoot, workflowTest);
builder.AddEdge(workflowTest, getMessagesAll);
// Build the workflow
return builder.Build();
}
}
@@ -0,0 +1,11 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_test
actions:
- kind: RetrieveConversationMessages
id: get_messages_all
messages: Local.AllMessages
conversationId: =System.ConversationId