.NET Workflows - Introduce support for Local variable scope (#944)

* Prepare for update

* Checkpoint

* Comments

* All fixed

* Mixed casre test added

* Rollback nuget

* Remove redundant restorable

* Namespace
This commit is contained in:
Chris
2025-09-26 21:44:19 +00:00
committed by GitHub
parent a9608465d9
commit 4d63899812
38 changed files with 242 additions and 207 deletions
+3 -3
View File
@@ -90,9 +90,9 @@
<!-- Identity -->
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.77.0" />
<!-- Workflows -->
<PackageVersion Include="Microsoft.Bot.ObjectModel" Version="1.2025.922-1" />
<PackageVersion Include="Microsoft.Bot.ObjectModel.Json" Version="1.2025.922-1" />
<PackageVersion Include="Microsoft.Bot.ObjectModel.PowerFx" Version="1.2025.922-1" />
<PackageVersion Include="Microsoft.Bot.ObjectModel" Version="1.2025.926-1" />
<PackageVersion Include="Microsoft.Bot.ObjectModel.Json" Version="1.2025.926-1" />
<PackageVersion Include="Microsoft.Bot.ObjectModel.PowerFx" Version="1.2025.926-1" />
<PackageVersion Include="Microsoft.PowerFx.Interpreter" Version="1.4.0-build.20250821-1001" />
<!-- Test -->
<PackageVersion Include="FluentAssertions" Version="8.6.0" />
@@ -17,7 +17,7 @@ namespace Microsoft.Agents.Workflows.Declarative;
public static class DeclarativeWorkflowBuilder
{
/// <summary>
/// Builds a process from the provided YAML definition of a CPS Topic ObjectModel.
/// Builds a workflow from the provided YAML definition.
/// </summary>
/// <typeparam name="TInput">The type of the input message</typeparam>
/// <param name="workflowFile">The path to the workflow.</param>
@@ -35,7 +35,7 @@ public static class DeclarativeWorkflowBuilder
}
/// <summary>
/// Builds a process from the provided YAML definition of a CPS Topic ObjectModel.
/// Builds a workflow from the provided YAML definition.
/// </summary>
/// <typeparam name="TInput">The type of the input message</typeparam>
/// <param name="yamlReader">The reader that provides the workflow object model YAML.</param>
@@ -71,7 +71,7 @@ public static class DeclarativeWorkflowBuilder
return visitor.Complete();
}
private static ChatMessage DefaultTransform(object message) =>
internal static ChatMessage DefaultTransform(object message) =>
message switch
{
ChatMessage chatMessage => chatMessage,
@@ -23,16 +23,16 @@ internal static class IWorkflowContextExtensions
context.SendMessageAsync(new ExecutorResultMessage(id, result));
public static ValueTask QueueStateResetAsync(this IWorkflowContext context, PropertyPath variablePath) =>
context.QueueStateUpdateAsync(Throw.IfNull(variablePath.VariableName), UnassignedValue.Instance, Throw.IfNull(variablePath.VariableScopeName));
context.QueueStateUpdateAsync(Throw.IfNull(variablePath.VariableName), UnassignedValue.Instance, Throw.IfNull(variablePath.NamespaceAlias));
public static ValueTask QueueStateUpdateAsync<TValue>(this IWorkflowContext context, PropertyPath variablePath, TValue? value) =>
context.QueueStateUpdateAsync(Throw.IfNull(variablePath.VariableName), value, Throw.IfNull(variablePath.VariableScopeName));
context.QueueStateUpdateAsync(Throw.IfNull(variablePath.VariableName), value, Throw.IfNull(variablePath.NamespaceAlias));
public static ValueTask QueueSystemUpdateAsync<TValue>(this IWorkflowContext context, string key, TValue? value) =>
DeclarativeContext(context).QueueSystemUpdateAsync(key, value);
public static FormulaValue ReadState(this IWorkflowContext context, PropertyPath variablePath) =>
context.ReadState(Throw.IfNull(variablePath.VariableName), Throw.IfNull(variablePath.VariableScopeName));
context.ReadState(Throw.IfNull(variablePath.VariableName), Throw.IfNull(variablePath.NamespaceAlias));
public static FormulaValue ReadState(this IWorkflowContext context, string key, string? scopeName = null) =>
DeclarativeContext(context).State.Get(key, scopeName);
@@ -51,7 +51,7 @@ internal static class IWorkflowContextExtensions
public static async ValueTask EnsureWorkflowConversationAsync(this IWorkflowContext context, WorkflowAgentProvider agentProvider, StringExpression expression, CancellationToken cancellationToken)
{
if (expression.IsVariableReference &&
expression.VariableReference.IsVariableReferenceWithScope(VariableScopeNames.System, out string? variableName))
expression.VariableReference.IsVariableReferenceWithScope(VariableNamespace.System, out string? variableName))
{
if (string.Equals(variableName, SystemScope.Names.Conversation, StringComparison.Ordinal) ||
string.Equals(variableName, SystemScope.Names.ConversationId, StringComparison.Ordinal))
@@ -16,6 +16,7 @@ internal sealed class DeclarativeWorkflowContext : IWorkflowContext
{
public static readonly FrozenSet<string> ManagedScopes =
[
VariableScopeNames.Local,
VariableScopeNames.Topic,
VariableScopeNames.Global,
];
@@ -211,6 +211,15 @@ internal sealed class WorkflowActionVisitor : DialogActionVisitor
this.RestartAfter(item.Id.Value, endExecutor.ParentId);
}
protected override void Visit(EndDialog item)
{
this.Trace(item);
DefaultActionExecutor endExecutor = new(item, this._workflowState);
this.ContinueWith(endExecutor);
this.RestartAfter(item.Id.Value, endExecutor.ParentId);
}
protected override void Visit(Question item)
{
this.Trace(item);
@@ -388,8 +397,6 @@ internal sealed class WorkflowActionVisitor : DialogActionVisitor
protected override void Visit(UnknownDialogAction item) => this.NotSupported(item);
protected override void Visit(EndDialog item) => this.NotSupported(item);
protected override void Visit(RepeatDialog item) => this.NotSupported(item);
protected override void Visit(ReplaceDialog item) => this.NotSupported(item);
@@ -6,11 +6,6 @@ namespace Microsoft.Agents.Workflows.Declarative.Interpreter;
internal sealed class WorkflowElementWalker : BotElementWalker
{
static WorkflowElementWalker()
{
ProductContext.SetContext(Product.Foundry);
}
private readonly DialogActionVisitor _visitor;
public WorkflowElementWalker(DialogActionVisitor visitor)
@@ -37,6 +37,7 @@
<ItemGroup>
<InternalsVisibleTo Include="Microsoft.Agents.Workflows.Declarative.UnitTests" />
<InternalsVisibleTo Include="Microsoft.Agents.Workflows.Declarative.IntegrationTests" />
</ItemGroup>
</Project>
@@ -17,8 +17,9 @@ internal static class RecalcEngineFactory
foreach (string scopeName in VariableScopeNames.AllScopes)
{
engine.UpdateVariable(scopeName, RecordValue.Empty());
engine.UpdateVariable(WorkflowFormulaState.GetScopeName(scopeName), RecordValue.Empty());
}
engine.UpdateVariable(VariableScopeNames.Topic, RecordValue.Empty());
return engine;
@@ -59,13 +59,13 @@ internal static class WorkflowDiagnostics
FormulaValue defaultValue = variableDiagnostic.ConstantValue?.ToFormula() ?? variableDiagnostic.Type.NewBlank();
if (variableDiagnostic.Path.VariableScopeName?.Equals(VariableScopeNames.System, StringComparison.OrdinalIgnoreCase) is true &&
if (variableDiagnostic.Path.NamespaceAlias?.Equals(VariableScopeNames.System, StringComparison.OrdinalIgnoreCase) is true &&
!SystemScope.AllNames.Contains(variableDiagnostic.Path.VariableName))
{
throw new DeclarativeModelException($"Variable '{variableDiagnostic.Path.VariableName}' is not a supported system variable.");
}
scopes.Set(variableDiagnostic.Path.VariableName, defaultValue, variableDiagnostic.Path.VariableScopeName ?? WorkflowFormulaState.DefaultScopeName);
scopes.Set(variableDiagnostic.Path.VariableName, defaultValue, variableDiagnostic.Path.NamespaceAlias ?? WorkflowFormulaState.DefaultScopeName);
}
}
@@ -17,12 +17,11 @@ namespace Microsoft.Agents.Workflows.Declarative.PowerFx;
/// </summary>
internal sealed class WorkflowFormulaState
{
// ISSUE #488 - Update default scope for workflows to `Workflow` (instead of `Topic`)
public const string DefaultScopeName = VariableScopeNames.Topic;
public const string DefaultScopeName = VariableScopeNames.Local;
public static readonly FrozenSet<string> RestorableScopes =
[
VariableScopeNames.Topic,
VariableScopeNames.Local,
VariableScopeNames.Global,
VariableScopeNames.System,
];
@@ -37,7 +36,8 @@ internal sealed class WorkflowFormulaState
public WorkflowFormulaState(RecalcEngine engine)
{
this._scopes = VariableScopeNames.AllScopes.ToDictionary(scopeName => scopeName, scopeName => new WorkflowScope());
this._scopes = VariableScopeNames.AllScopes.ToDictionary(scopeName => GetScopeName(scopeName), _ => new WorkflowScope());
this.Engine = engine;
this.Evaluator = new WorkflowExpressionEngine(engine);
this.Bind();
@@ -87,11 +87,15 @@ internal sealed class WorkflowFormulaState
}
}
public void Bind(string? targetScope = null)
public void Bind(string? scopeNameToBind = null)
{
if (targetScope is not null)
if (scopeNameToBind is not null)
{
Bind(targetScope);
Bind(scopeNameToBind);
if (VariableScopeNames.GetNamespaceFromName(scopeNameToBind) == VariableNamespace.Component)
{
Bind(scopeNameToBind, VariableScopeNames.Topic);
}
}
else
{
@@ -99,26 +103,38 @@ internal sealed class WorkflowFormulaState
{
Bind(scopeName);
}
Bind(DefaultScopeName, VariableScopeNames.Topic);
}
void Bind(string scopeName)
void Bind(string scopeName, string? targetScope = null)
{
targetScope = GetScopeName(targetScope ?? scopeName);
RecordValue scopeRecord = this.GetScope(scopeName).ToRecord();
this.Engine.DeleteFormula(scopeName);
this.Engine.UpdateVariable(scopeName, scopeRecord);
this.Engine.DeleteFormula(targetScope);
this.Engine.UpdateVariable(targetScope, scopeRecord);
}
}
private WorkflowScope GetScope(string? scopeName)
{
scopeName ??= DefaultScopeName;
private WorkflowScope GetScope(string? scopeName) => this._scopes[GetScopeName(scopeName)];
if (!VariableScopeNames.IsValidName(scopeName))
public static string GetScopeName(string? scopeName)
{
if (!ProductContext.IsLocalScopeSupported())
{
throw new DeclarativeActionException($"Invalid variable scope name: '{scopeName}'.");
ProductContext.SetContext(Product.Foundry);
}
return this._scopes[scopeName];
scopeName ??= DefaultScopeName;
return
VariableScopeNames.GetNamespaceFromName(scopeName) switch
{
// Always alias component level scope as "Local"
VariableNamespace.Component => DefaultScopeName,
VariableNamespace.Unknown => throw new DeclarativeActionException($"Invalid variable scope name: '{scopeName}'."),
_ => scopeName,
};
}
/// <summary>
@@ -2,7 +2,7 @@
using System;
using System.Reflection;
using Microsoft.Bot.ObjectModel;
using Microsoft.Agents.Workflows.Declarative.PowerFx;
using Microsoft.Extensions.Configuration;
using Xunit.Abstractions;
@@ -35,7 +35,7 @@ public abstract class WorkflowTest : IDisposable
}
}
internal static string FormatVariablePath(string variableName, string? scope = null) => $"{scope ?? VariableScopeNames.Topic}.{variableName}";
internal static string FormatVariablePath(string variableName, string? scope = null) => $"{scope ?? WorkflowFormulaState.DefaultScopeName}.{variableName}";
protected static IConfigurationRoot InitializeConfig() =>
new ConfigurationBuilder()
@@ -7,23 +7,23 @@ trigger:
- kind: CreateConversation
id: conversation_create1
conversationId: Topic.FirstConversationId
conversationId: Local.FirstConversationId
- kind: CreateConversation
id: conversation_create2
conversationId: Topic.SecondConversationId
conversationId: Local.SecondConversationId
- kind: SendActivity
id: sendActivity_conversation
activity: |-
Conversation 1: {Topic.FirstConversationId}
Conversation 2: {Topic.SecondConversationId}
Conversation 1: {Local.FirstConversationId}
Conversation 2: {Local.SecondConversationId}
- kind: AddConversationMessage
id: add_message
message: Topic.MyMessage1
message: Local.MyMessage1
role: User
conversationId: =Topic.FirstConversationId
conversationId: =Local.FirstConversationId
content:
- type: Text
value: {System.LastMessage.Text}
@@ -31,12 +31,12 @@ trigger:
- kind: SendActivity
id: sendActivity_message
activity: |-
Messsage 1: {Topic.MyMessage1}
Messsage 1: {Local.MyMessage1}
- kind: CopyConversationMessages
id: copy_messages
conversationId: =Topic.SecondConversationId
messages: =[Topic.MyMessage1]
conversationId: =Local.SecondConversationId
messages: =[Local.MyMessage1]
- kind: SendActivity
id: sendActivity_copy
@@ -7,11 +7,11 @@ trigger:
- kind: RetrieveConversationMessage
id: get_message
message: Topic.MyMessage
message: Local.MyMessage
conversationId: thread_T8xIzNrNcPkUkoCEGzxg80Vt
messageId: msg_J4x6YZTDUUWNs60FOUAucldy
- kind: SendActivity
id: sendActivity_message
activity: |-
{Topic.MyMessage}
{Local.MyMessage}
@@ -7,10 +7,10 @@ trigger:
- kind: RetrieveConversationMessages
id: get_message
messages: Topic.MyMessages
messages: Local.MyMessages
conversationId: thread_T8xIzNrNcPkUkoCEGzxg80Vt
- kind: SendActivity
id: sendActivity_message
activity: |-
{Topic.MyMessages}
{Local.MyMessages}
@@ -12,4 +12,4 @@ trigger:
input:
messages: =[UserMessage(System.LastMessageText)]
output:
messages: Topic.Answer
messages: Local.Answer
@@ -8,7 +8,7 @@ trigger:
# Capture input
- kind: SetVariable
id: set_user_input
variable: Topic.UserInput
variable: Local.UserInput
value: =System.LastMessage.Text
# Capture environment variable
@@ -22,4 +22,4 @@ trigger:
id: send_result
activity: |-
Hello {Global.UserName},
You said, "{Topic.UserInput}"
You said, "{Local.UserInput}"
@@ -7,7 +7,6 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.Agents.Workflows.Declarative.Interpreter;
using Microsoft.Agents.Workflows.Declarative.PowerFx;
using Microsoft.Agents.Workflows.Reflection;
using Microsoft.Bot.ObjectModel;
using Moq;
using Xunit.Abstractions;
@@ -140,7 +139,8 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
}
[Theory]
[InlineData("Single.yaml", 1, "end_all")]
[InlineData("EndConversation.yaml", 1, "end_all")]
[InlineData("EndDialog.yaml", 1, "end_all")]
[InlineData("EditTable.yaml", 2, "edit_var")]
[InlineData("EditTableV2.yaml", 2, "edit_var")]
[InlineData("ParseValue.yaml", 1, "parse_var")]
@@ -149,6 +149,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
[InlineData("SetTextVariable.yaml", 1, "set_text")]
[InlineData("ClearAllVariables.yaml", 1, "clear_all")]
[InlineData("ResetVariable.yaml", 2, "clear_var")]
[InlineData("MixedScopes.yaml", 2, "activity_input")]
public async Task ExecuteActionAsync(string workflowFile, int expectedCount, string expectedId)
{
await this.RunWorkflowAsync(workflowFile);
@@ -168,7 +169,6 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
[InlineData(typeof(DisableTrigger.Builder))]
[InlineData(typeof(DisconnectedNodeContainer.Builder))]
[InlineData(typeof(EmitEvent.Builder))]
[InlineData(typeof(EndDialog.Builder))]
[InlineData(typeof(GetActivityMembers.Builder))]
[InlineData(typeof(GetConversationMembers.Builder))]
[InlineData(typeof(HttpRequestAction.Builder))]
@@ -211,7 +211,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
WorkflowFormulaState state = new(RecalcEngineFactory.Create());
Mock<WorkflowAgentProvider> mockAgentProvider = new(MockBehavior.Strict);
DeclarativeWorkflowOptions options = new(mockAgentProvider.Object);
WorkflowActionVisitor visitor = new(new RootExecutor(), state, options);
WorkflowActionVisitor visitor = new(new DeclarativeWorkflowExecutor<string>(WorkflowActionVisitor.Steps.Root("anything"), state, (message) => DeclarativeWorkflowBuilder.DefaultTransform(message)), state, options);
WorkflowElementWalker walker = new(visitor);
walker.Visit(dialog);
Assert.True(visitor.HasUnsupportedActions);
@@ -244,7 +244,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
Assert.Contains(this.WorkflowEvents.OfType<MessageActivityEvent>(), e => string.Equals(e.Message.Trim(), message, StringComparison.Ordinal));
private Task RunWorkflowAsync(string workflowPath) =>
this.RunWorkflowAsync(workflowPath, string.Empty);
this.RunWorkflowAsync(workflowPath, "Test input message");
private async Task RunWorkflowAsync<TInput>(string workflowPath, TInput workflowInput) where TInput : notnull
{
@@ -272,6 +272,10 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
{
this.Output.WriteLine($"ACTION EXIT: {actionCompleteEvent.ActionId}");
}
else if (workflowEvent is MessageActivityEvent activityEvent)
{
this.Output.WriteLine($"ACTIVITY: {activityEvent.Message}");
}
else if (workflowEvent is AgentRunResponseEvent messageEvent)
{
this.Output.WriteLine($"MESSAGE: {messageEvent.Response.Messages[0].Text.Trim()}");
@@ -279,12 +283,4 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
}
this.WorkflowEventCounts = this.WorkflowEvents.GroupBy(e => e.GetType()).ToDictionary(e => e.Key, e => e.Count());
}
private sealed class RootExecutor() :
ReflectingExecutor<RootExecutor>(WorkflowActionVisitor.Steps.Root("anything")),
IMessageHandler<string>
{
public async ValueTask HandleAsync(string message, IWorkflowContext context) =>
await context.SendMessageAsync($"{this.Id}: {DateTime.UtcNow:t}").ConfigureAwait(false);
}
}
@@ -42,7 +42,7 @@ public abstract class WorkflowActionExecutorTest(ITestOutputHelper output) : Wor
Assert.Equal(model, action.Model);
}
protected void VerifyState(string variableName, FormulaValue expectedValue) => this.VerifyState(variableName, VariableScopeNames.Topic, expectedValue);
protected void VerifyState(string variableName, FormulaValue expectedValue) => this.VerifyState(variableName, WorkflowFormulaState.DefaultScopeName, expectedValue);
internal void VerifyState(string variableName, string scopeName, FormulaValue expectedValue)
{
@@ -50,9 +50,7 @@ public abstract class WorkflowActionExecutorTest(ITestOutputHelper output) : Wor
Assert.Equal(expectedValue.Format(), actualValue.Format());
}
protected void VerifyUndefined(string variableName) => this.VerifyUndefined(variableName, VariableScopeNames.Topic);
internal void VerifyUndefined(string variableName, string scopeName) =>
internal void VerifyUndefined(string variableName, string? scopeName = null) =>
Assert.IsType<BlankValue>(this.State.Get(variableName, scopeName));
protected static TAction AssignParent<TAction>(DialogAction.Builder actionBuilder) where TAction : DialogAction
@@ -34,14 +34,14 @@ public class WorkflowExpressionEngineTests : RecalcEngineTest
: base(output)
{
this.State.Set(Variables.GlobalValue, FormulaValue.New(255), VariableScopeNames.Global);
this.State.Set(Variables.BoolValue, FormulaValue.New(true), VariableScopeNames.Topic);
this.State.Set(Variables.StringValue, FormulaValue.New("Hello World"), VariableScopeNames.Topic);
this.State.Set(Variables.IntValue, FormulaValue.New(long.MaxValue), VariableScopeNames.Topic);
this.State.Set(Variables.NumberValue, FormulaValue.New(33.3), VariableScopeNames.Topic);
this.State.Set(Variables.EnumValue, FormulaValue.New(nameof(VariablesToClear.ConversationScopedVariables)), VariableScopeNames.Topic);
this.State.Set(Variables.ObjectValue, ObjectData, VariableScopeNames.Topic);
this.State.Set(Variables.ArrayValue, TableData, VariableScopeNames.Topic);
this.State.Set(Variables.BlankValue, FormulaValue.NewBlank(), VariableScopeNames.Topic);
this.State.Set(Variables.BoolValue, FormulaValue.New(true));
this.State.Set(Variables.StringValue, FormulaValue.New("Hello World"));
this.State.Set(Variables.IntValue, FormulaValue.New(long.MaxValue));
this.State.Set(Variables.NumberValue, FormulaValue.New(33.3));
this.State.Set(Variables.EnumValue, FormulaValue.New(nameof(VariablesToClear.ConversationScopedVariables)));
this.State.Set(Variables.ObjectValue, ObjectData);
this.State.Set(Variables.ArrayValue, TableData);
this.State.Set(Variables.BlankValue, FormulaValue.NewBlank());
this.State.Bind();
}
@@ -15,7 +15,7 @@ public class WorkflowFormulaStateTests
{
// Arrange
FormulaValue testValue = FormulaValue.New("test");
this.State.Set("key1", testValue, VariableScopeNames.Topic);
this.State.Set("key1", testValue);
// Act
FormulaValue result = this.State.Get("key1");
@@ -48,7 +48,7 @@ public class WorkflowFormulaStateTests
this.State.Set("key1", testValue);
// Assert
FormulaValue result = this.State.Get("key1", VariableScopeNames.Topic);
FormulaValue result = this.State.Get("key1");
Assert.Equal(testValue, result);
}
@@ -74,11 +74,11 @@ public class WorkflowFormulaStateTests
FormulaValue newValue = FormulaValue.New("new");
// Act
this.State.Set("key1", initialValue, VariableScopeNames.Topic);
this.State.Set("key1", newValue, VariableScopeNames.Topic);
this.State.Set("key1", initialValue);
this.State.Set("key1", newValue);
// Assert
FormulaValue result = this.State.Get("key1", VariableScopeNames.Topic);
FormulaValue result = this.State.Get("key1");
Assert.Equal(newValue, result);
}
}
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using Microsoft.Bot.ObjectModel;
using Microsoft.Agents.Workflows.Declarative.PowerFx;
using Xunit.Abstractions;
namespace Microsoft.Agents.Workflows.Declarative.UnitTests;
@@ -36,5 +36,5 @@ public abstract class WorkflowTest : IDisposable
internal static string? FormatOptionalPath(string? variableName, string? scope = null) =>
variableName is null ? null : FormatVariablePath(variableName, scope);
internal static string FormatVariablePath(string variableName, string? scope = null) => $"{scope ?? VariableScopeNames.Topic}.{variableName}";
internal static string FormatVariablePath(string variableName, string? scope = null) => $"{scope ?? WorkflowFormulaState.DefaultScopeName}.{variableName}";
}
@@ -7,21 +7,21 @@ trigger:
- kind: SetVariable
id: setVariable_test
variable: Topic.TestValue
variable: Local.TestValue
value: =Value(System.LastMessageText)
- kind: ConditionGroup
id: conditionGroup_test
conditions:
- id: conditionItem_odd
condition: =Mod(Topic.TestValue, 2) = 1
condition: =Mod(Local.TestValue, 2) = 1
actions:
- kind: SendActivity
id: sendActivity_odd
activity: ODD
- id: conditionItem_even
condition: =Mod(Topic.TestValue, 2) = 0
condition: =Mod(Local.TestValue, 2) = 0
actions:
- kind: SendActivity
id: sendActivity_even
@@ -7,14 +7,14 @@ trigger:
- kind: SetVariable
id: setVariable_test
variable: Topic.TestValue
variable: Local.TestValue
value: =Value(System.LastMessageText)
- kind: ConditionGroup
id: conditionGroup_test
conditions:
- id: conditionItem_odd
condition: =Mod(Topic.TestValue, 2) = 1
condition: =Mod(Local.TestValue, 2) = 1
actions:
- kind: SendActivity
id: sendActivity_odd
@@ -7,11 +7,11 @@ trigger:
- kind: SetVariable
id: set_var
variable: Topic.MyTable
variable: Local.MyTable
value: =[{id: 3}]
- kind: EditTable
id: edit_var
itemsVariable: Topic.MyTable
itemsVariable: Local.MyTable
changeType: Add
value: ={id: 7}
@@ -7,12 +7,12 @@ trigger:
- kind: SetVariable
id: set_var
variable: Topic.MyTable
variable: Local.MyTable
value: =[{id: 3}]
- kind: EditTableV2
id: edit_var
itemsVariable: Topic.MyTable
itemsVariable: Local.MyTable
changeType:
kind: AddItemOperation
value: ={id: 7}
@@ -5,5 +5,9 @@ trigger:
id: my_workflow
actions:
- kind: EndConversation
- kind: EndDialog
id: end_all
- kind: SendActivity
id: send_activity_1
activity: NEVER 1!
@@ -7,24 +7,24 @@ trigger:
- kind: SetVariable
id: setVariable_count
variable: Topic.Count
variable: Local.Count
value: =0
- kind: Foreach
id: foreach_loop
items: =["a", "b", "c", "d", "e", "f"]
index: Topic.LoopIndex
value: Topic.LoopValue
index: Local.LoopIndex
value: Local.LoopValue
actions:
- kind: BreakLoop
id: breakLoop_now
- kind: SetVariable
id: setVariable_loop
variable: Topic.Count
value: =Topic.Count + 1
variable: Local.Count
value: =Local.Count + 1
- kind: SendActivity
id: sendActivity_loop
activity: x{Topic.Count} - {Topic.LoopIndex}:{Topic.LoopValue}
activity: x{Local.Count} - {Local.LoopIndex}:{Local.LoopValue}
- kind: EndConversation
id: end_all
@@ -7,24 +7,24 @@ trigger:
actions:
- kind: SetVariable
id: setVariable_count
variable: Topic.Count
variable: Local.Count
value: =0
- kind: Foreach
id: foreach_loop
items: =["a", "b", "c", "d", "e", "f"]
index: Topic.LoopIndex
value: Topic.LoopValue
index: Local.LoopIndex
value: Local.LoopValue
actions:
- kind: ContinueLoop
id: continueLoop_now
- kind: SetVariable
id: setVariable_loop
variable: Topic.Count
value: =Topic.Count + 1
variable: Local.Count
value: =Local.Count + 1
- kind: SendActivity
id: sendActivity_loop
activity: x{Topic.Count} - {Topic.LoopIndex}:{Topic.LoopValue}
activity: x{Local.Count} - {Local.LoopIndex}:{Local.LoopValue}
- kind: EndConversation
id: end_all
@@ -7,22 +7,22 @@ trigger:
actions:
- kind: SetVariable
id: setVariable_count
variable: Topic.Count
variable: Local.Count
value: =0
- kind: Foreach
id: foreach_loop
items: =["a", "b", "c", "d", "e", "f"]
index: Topic.LoopIndex
value: Topic.LoopValue
index: Local.LoopIndex
value: Local.LoopValue
actions:
- kind: SetVariable
id: setVariable_loop
variable: Topic.Count
value: =Topic.Count + 1
variable: Local.Count
value: =Local.Count + 1
- kind: SendActivity
id: sendActivity_loop
activity: x{Topic.Count} - {Topic.LoopIndex}:{Topic.LoopValue}
activity: x{Local.Count} - {Local.LoopIndex}:{Local.LoopValue}
- kind: EndConversation
id: end_all
@@ -0,0 +1,16 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: my_workflow
actions:
- kind: SetVariable
id: set_input
variable: Topic.TestValue
value: =System.LastMessageText
- kind: SendActivity
id: activity_input
activity: |-
Input: "{Local.TestValue}"
@@ -7,6 +7,6 @@ trigger:
actions:
- kind: ParseValue
id: parse_var
variable: Topic.MyVar
variable: Local.MyVar
value: "42"
valueType: Number
@@ -7,9 +7,9 @@ trigger:
- kind: SetVariable
id: set_var
variable: Topic.MyVar
variable: Local.MyVar
value: 42
- kind: ResetVariable
id: clear_var
variable: Topic.MyVar
variable: Local.MyVar
@@ -7,10 +7,10 @@ trigger:
- kind: SetVariable
id: set_input
variable: Topic.TestValue
variable: Local.TestValue
value: =System.LastMessageText
- kind: SendActivity
id: activity_input
activity: |-
Input: {Topic.TestValue}
Input: "{Local.TestValue}"
@@ -7,5 +7,5 @@ trigger:
- kind: SetTextVariable
id: set_text
variable: Topic.TestVar
variable: Local.TestVar
value: Test content
@@ -7,5 +7,5 @@ trigger:
- kind: SetVariable
id: set_var
variable: Topic.TestVar
variable: Local.TestVar
value: =3