diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Interpreter/DeclarativeWorkflowExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Interpreter/DeclarativeWorkflowExecutor.cs index 52cd02f916..7436e64446 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Interpreter/DeclarativeWorkflowExecutor.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Interpreter/DeclarativeWorkflowExecutor.cs @@ -40,8 +40,8 @@ internal sealed class DeclarativeWorkflowExecutor( } await declarativeContext.QueueConversationUpdateAsync(conversationId, isExternal: true, cancellationToken).ConfigureAwait(false); - await options.AgentProvider.CreateMessageAsync(conversationId, input, cancellationToken).ConfigureAwait(false); - await declarativeContext.SetLastMessageAsync(input).ConfigureAwait(false); + ChatMessage inputMessage = await options.AgentProvider.CreateMessageAsync(conversationId, input, cancellationToken).ConfigureAwait(false); + await declarativeContext.SetLastMessageAsync(inputMessage).ConfigureAwait(false); await context.SendResultMessageAsync(this.Id, cancellationToken).ConfigureAwait(false); } diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/RootExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/RootExecutor.cs index 1254440342..4439207701 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/RootExecutor.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/RootExecutor.cs @@ -67,8 +67,8 @@ public abstract class RootExecutor : Executor, IResettableExecut } await declarativeContext.QueueConversationUpdateAsync(this._conversationId, isExternal: true, cancellationToken).ConfigureAwait(false); - await this._agentProvider.CreateMessageAsync(this._conversationId, input, cancellationToken).ConfigureAwait(false); - await declarativeContext.SetLastMessageAsync(input).ConfigureAwait(false); + ChatMessage inputMessage = await this._agentProvider.CreateMessageAsync(this._conversationId, input, cancellationToken).ConfigureAwait(false); + await declarativeContext.SetLastMessageAsync(inputMessage).ConfigureAwait(false); await declarativeContext.SendResultMessageAsync(this.Id, cancellationToken).ConfigureAwait(false); } diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/PowerFx/WorkflowExpressionEngine.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/PowerFx/WorkflowExpressionEngine.cs index 17a013cb11..fa3ae6b32d 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/PowerFx/WorkflowExpressionEngine.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/PowerFx/WorkflowExpressionEngine.cs @@ -274,6 +274,13 @@ internal sealed class WorkflowExpressionEngine expression.VariableReference?.ToString() : expression.ExpressionText; - return new(this._engine.Eval(expressionText), SensitivityLevel.None); + FormulaValue result = this._engine.Eval(expressionText); + + if (result is ErrorValue errorValue) + { + throw new DeclarativeActionException(errorValue.Format()); + } + + return new(result, SensitivityLevel.None); } } diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeCodeGenTest.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeCodeGenTest.cs index 2ad0782602..7044f5ca70 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeCodeGenTest.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeCodeGenTest.cs @@ -15,6 +15,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests; public sealed class DeclarativeCodeGenTest(ITestOutputHelper output) : WorkflowTest(output) { [Theory] + [InlineData("CheckSystem.yaml", "CheckSystem.json")] [InlineData("SendActivity.yaml", "SendActivity.json")] [InlineData("InvokeAgent.yaml", "InvokeAgent.json")] [InlineData("InvokeAgent.yaml", "InvokeAgent.json", true)] diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeWorkflowTest.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeWorkflowTest.cs index 00f9c59ada..fad4e7b8f7 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeWorkflowTest.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/DeclarativeWorkflowTest.cs @@ -15,6 +15,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests; public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : WorkflowTest(output) { [Theory] + [InlineData("CheckSystem.yaml", "CheckSystem.json")] [InlineData("SendActivity.yaml", "SendActivity.json")] [InlineData("InvokeAgent.yaml", "InvokeAgent.json")] [InlineData("InvokeAgent.yaml", "InvokeAgent.json", true)] diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Testcases/CheckSystem.json b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Testcases/CheckSystem.json new file mode 100644 index 0000000000..2e7d4b6f8d --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Testcases/CheckSystem.json @@ -0,0 +1,24 @@ +{ + "description": "Send an activity message.", + "setup": { + "input": { + "type": "String", + "value": "Everything good?" + } + }, + "validation": { + "conversation_count": 1, + "min_action_count": 2, + "max_action_count": -1, + "min_response_count": 0, + "actions": { + "start": [ + "check_system" + ], + "final": [ + "activity_passed", + "check_system_Post" + ] + } + } +} \ No newline at end of file diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Workflows/CheckSystem.yaml b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Workflows/CheckSystem.yaml new file mode 100644 index 0000000000..c3542fb057 --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/Workflows/CheckSystem.yaml @@ -0,0 +1,57 @@ +kind: Workflow +trigger: + + kind: OnConversationStart + id: workflow_test + actions: + + - kind: ConditionGroup + id: check_system + conditions: + + - condition: =IsBlank(System.Conversation) + id: conversation_check + actions: + - kind: EndDialog + id: conversation_bad + + - condition: =IsBlank(System.Conversation.Id) + id: conversation_id_check1 + actions: + - kind: EndDialog + id: conversation_id_bad1 + + - condition: =IsBlank(System.ConversationId) + id: conversation_id_check2 + actions: + - kind: EndDialog + id: conversation_id_bad2 + + - condition: =IsBlank(System.LastMessage) + id: message_check + actions: + - kind: EndDialog + id: message_bad + + - condition: =IsBlank(System.LastMessage.Id) + id: message_id_check1 + actions: + - kind: EndDialog + id: message_id_bad1 + + - condition: =IsBlank(System.LastMessageId) + id: message_id_check2 + actions: + - kind: EndDialog + id: message_id_bad2 + + - condition: =IsBlank(System.LastMessageText) + id: message_text_check + actions: + - kind: EndDialog + id: message_text_bad + + elseActions: + - kind: SendActivity + id: activity_passed + activity: PASSED! diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DeclarativeWorkflowTest.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DeclarativeWorkflowTest.cs index 63d109161e..7d7aee5418 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DeclarativeWorkflowTest.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DeclarativeWorkflowTest.cs @@ -215,7 +215,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow AdaptiveDialog dialog = dialogBuilder.Build(); WorkflowFormulaState state = new(RecalcEngineFactory.Create()); - Mock mockAgentProvider = CreateMockProvider(); + Mock mockAgentProvider = CreateMockProvider("1"); DeclarativeWorkflowOptions options = new(mockAgentProvider.Object); WorkflowActionVisitor visitor = new(new DeclarativeWorkflowExecutor(WorkflowActionVisitor.Steps.Root("anything"), options, state, (message) => DeclarativeWorkflowBuilder.DefaultTransform(message)), state, options); WorkflowElementWalker walker = new(visitor); @@ -255,7 +255,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow private async Task RunWorkflowAsync(string workflowPath, TInput workflowInput) where TInput : notnull { using StreamReader yamlReader = File.OpenText(Path.Combine("Workflows", workflowPath)); - Mock mockAgentProvider = CreateMockProvider(); + Mock mockAgentProvider = CreateMockProvider($"{workflowInput}"); DeclarativeWorkflowOptions workflowContext = new(mockAgentProvider.Object) { LoggerFactory = this.Output }; Workflow workflow = DeclarativeWorkflowBuilder.Build(yamlReader, workflowContext); @@ -301,11 +301,11 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow this.WorkflowEventCounts = this.WorkflowEvents.GroupBy(e => e.GetType()).ToDictionary(e => e.Key, e => e.Count()); } - private static Mock CreateMockProvider() + private static Mock CreateMockProvider(string input) { Mock mockAgentProvider = new(MockBehavior.Strict); mockAgentProvider.Setup(provider => provider.CreateConversationAsync(It.IsAny())).Returns(() => Task.FromResult(Guid.NewGuid().ToString("N"))); - mockAgentProvider.Setup(provider => provider.CreateMessageAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new ChatMessage(ChatRole.Assistant, "Hi!"))); + mockAgentProvider.Setup(provider => provider.CreateMessageAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new ChatMessage(ChatRole.Assistant, input))); return mockAgentProvider; } }