.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 14:44:19 -07:00
committed by GitHub
Unverified
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
+72 -72
View File
@@ -39,7 +39,7 @@ trigger:
- kind: SetVariable
id: setVariable_aASlmF
displayName: List all available agents for this orchestrator
variable: Topic.AvailableAgents
variable: Local.AvailableAgents
value: |-
=[
{
@@ -62,20 +62,20 @@ trigger:
- kind: SetVariable
id: setVariable_V6yEbo
displayName: Get a summary of all the agents for use in prompts
variable: Topic.TeamDescription
value: "=Concat(ForAll(Topic.AvailableAgents, $\"- \" & name & $\": \" & description), Value, \"\n\")"
variable: Local.TeamDescription
value: "=Concat(ForAll(Local.AvailableAgents, $\"- \" & name & $\": \" & description), Value, \"\n\")"
- kind: SetVariable
id: setVariable_NZ2u0l
displayName: Set Task
variable: Topic.InputTask
variable: Local.InputTask
value: =System.LastMessage.Text
- kind: SetVariable
id: setVariable_10u2ZN
displayName: Set Task
variable: Topic.SeedTask
value: =Topic.InputTask
variable: Local.SeedTask
value: =Local.InputTask
- kind: SendActivity
id: sendActivity_yFsbRy
@@ -83,18 +83,18 @@ trigger:
- kind: CreateConversation
id: conversation_1a2b3c
conversationId: Topic.InternalConversationId
conversationId: Local.InternalConversationId
- kind: InvokeAzureAgent
id: question_UDoMUw
displayName: Get Facts
conversationId: =Topic.InternalConversationId
conversationId: =Local.InternalConversationId
agent:
name: =Env.FOUNDRY_AGENT_RESEARCHANALYST
output:
messages: Topic.TaskFacts
messages: Local.TaskFacts
input:
messages: =[UserMessage(Topic.InputTask)]
messages: =[UserMessage(Local.InputTask)]
additionalInstructions: |-
In order to help begin addressing the user request, please answer the following pre-survey to the best of your ability.
Keep in mind that you are Ken Jennings-level with trivia, and Mensa-level with puzzles, so there should be a deep well to draw from.
@@ -122,19 +122,19 @@ trigger:
- kind: InvokeAzureAgent
id: question_DsBaJU
displayName: Create a Plan
conversationId: =Topic.InternalConversationId
conversationId: =Local.InternalConversationId
agent:
name: =Env.FOUNDRY_AGENT_RESEARCHMANAGER
output:
messages: Topic.Plan
messages: Local.Plan
input:
messages: =[UserMessage(Topic.InputTask)]
messages: =[UserMessage(Local.InputTask)]
additionalInstructions: |-
Your only job is to devise an efficient plan that identifies (by name) how a team member may contribute to addressing the user request.
Only select the following team which is listed as "- [Name]: [Description]"
{Topic.TeamDescription}
{Local.TeamDescription}
The plan must be a bullet point list must be in the form "- [AgentName]: [Specific action or task for that agent to perform]"
@@ -143,60 +143,60 @@ trigger:
- kind: SetVariable
id: setVariable_Kk2LDL
displayName: Define instructions
variable: Topic.TaskInstructions
variable: Local.TaskInstructions
value: |-
="# TASK
Address the following user request:
" & Topic.InputTask & "
" & Local.InputTask & "
# TEAM
Use the following team to answer this request:
" & Topic.TeamDescription & "
" & Local.TeamDescription & "
# FACTS
Consider this initial fact sheet:
" & Trim(Topic.TaskFacts.Text) & "
" & Trim(Local.TaskFacts.Text) & "
# PLAN
Here is the plan to follow as best as possible:
" & Topic.Plan.Text
" & Local.Plan.Text
- kind: SendActivity
id: sendActivity_bwNZiM
activity: {Topic.TaskInstructions}
activity: {Local.TaskInstructions}
- kind: InvokeAzureAgent
id: question_o3BQkf
displayName: Progress Ledger Prompt
conversationId: =Topic.InternalConversationId
conversationId: =Local.InternalConversationId
agent:
name: =Env.FOUNDRY_AGENT_RESEARCHMANAGER
output:
messages: Topic.ProgressLedgerUpdate
messages: Local.ProgressLedgerUpdate
input:
messages: =[UserMessage(Topic.AgentResponseText)]
messages: =[UserMessage(Local.AgentResponseText)]
additionalInstructions: |-
Recall we are working on the following request:
{Topic.InputTask}
{Local.InputTask}
And we have assembled the following team:
{Topic.TeamDescription}
{Local.TeamDescription}
To make progress on the request, please answer the following questions, including necessary reasoning:
- Is the request fully satisfied? (True if complete, or False if the original request has yet to be SUCCESSFULLY and FULLY addressed)
- Are we in a loop where we are repeating the same requests and / or getting the same responses from an agent multiple times? Loops can span multiple turns, and can include repeated actions like scrolling up or down more than a handful of times.
- Are we making forward progress? (True if just starting, or recent messages are adding value. False if recent messages show evidence of being stuck in a loop or if there is evidence of significant barriers to success such as the inability to read from a required file)
- Who should speak next? (select from: {Concat(Topic.AvailableAgents, name, ",")})
- Who should speak next? (select from: {Concat(Local.AvailableAgents, name, ",")})
- What instruction or question would you give this team member? (Phrase as if speaking directly to them, and include any specific information they may need)
Please output an answer in pure JSON format according to the following schema. The JSON object must be parsable as-is. DO NOT OUTPUT ANYTHING OTHER THAN JSON, AND DO NOT DEVIATE FROM THIS SCHEMA:
@@ -216,7 +216,7 @@ trigger:
}},
"next_speaker": {{
"reason": string,
"answer": string (select from: {Concat(Topic.AvailableAgents, name, ",")})
"answer": string (select from: {Concat(Local.AvailableAgents, name, ",")})
}},
"instruction_or_question": {{
"reason": string,
@@ -227,8 +227,8 @@ trigger:
- kind: ParseValue
id: parse_rNZtlV
displayName: Parse ledger response
variable: Topic.TypedProgressLedger
value: =Topic.ProgressLedgerUpdate.Text
variable: Local.TypedProgressLedger
value: =Local.ProgressLedgerUpdate.Text
valueType:
kind: Record
properties:
@@ -271,13 +271,13 @@ trigger:
id: conditionGroup_mVIecC
conditions:
- id: conditionItem_fj432c
condition: =Topic.TypedProgressLedger.is_request_satisfied.answer
condition: =Local.TypedProgressLedger.is_request_satisfied.answer
displayName: If Done
actions:
- kind: SendActivity
id: sendActivity_kdl3mC
activity: Completed! {Topic.TypedProgressLedger.is_request_satisfied.reason}
activity: Completed! {Local.TypedProgressLedger.is_request_satisfied.reason}
- kind: InvokeAzureAgent
id: question_Ke3l1d
@@ -286,9 +286,9 @@ trigger:
agent:
name: =Env.FOUNDRY_AGENT_RESEARCHMANAGER
output:
messages: Topic.FinalResponse
messages: Local.FinalResponse
input:
messages: =[UserMessage(Topic.SeedTask)]
messages: =[UserMessage(Local.SeedTask)]
additionalInstructions: |-
We have completed the task.
Based only on the conversation and without adding any new information, synthesize the result of the conversation as a complete response to the user task.
@@ -298,15 +298,15 @@ trigger:
id: end_SVoNSV
- id: conditionItem_yiqund
condition: =Topic.TypedProgressLedger.is_in_loop.answer || Not(Topic.TypedProgressLedger.is_progress_being_made.answer)
condition: =Local.TypedProgressLedger.is_in_loop.answer || Not(Local.TypedProgressLedger.is_progress_being_made.answer)
displayName: If Stalling
actions:
- kind: SetVariable
id: setVariable_H5lXdD
displayName: Increase stall count
variable: Topic.StallCount
value: =Topic.StallCount + 1
variable: Local.StallCount
value: =Local.StallCount + 1
- kind: ConditionGroup
@@ -319,22 +319,22 @@ trigger:
actions:
- kind: SendActivity
id: sendActivity_fpaNL9
activity: {Topic.TypedProgressLedger.is_in_loop.reason}
activity: {Local.TypedProgressLedger.is_in_loop.reason}
- id: conditionItem_NnqvXh
condition: =Not(Topic.TypedProgressLedger.is_progress_being_made.answer)
condition: =Not(Local.TypedProgressLedger.is_progress_being_made.answer)
displayName: Is No Progress
actions:
- kind: SendActivity
id: sendActivity_NnqvXh
activity: {Topic.TypedProgressLedger.is_progress_being_made.reason}
activity: {Local.TypedProgressLedger.is_progress_being_made.reason}
- kind: ConditionGroup
id: conditionGroup_xzNrdM
conditions:
- id: conditionItem_NlQTBv
condition: =Topic.StallCount > 2
condition: =Local.StallCount > 2
displayName: Stall Count Exceeded
actions:
@@ -346,11 +346,11 @@ trigger:
id: conditionGroup_4s1Z27
conditions:
- id: conditionItem_EXAlhZ
condition: =Topic.RestartCount > 2
condition: =Local.RestartCount > 2
actions:
- kind: SendActivity
id: sendActivity_xKxFUU
activity: Stopping after attempting {Topic.RestartCount} restarts...
activity: Stopping after attempting {Local.RestartCount} restarts...
- kind: EndConversation
id: end_GHVrFh
@@ -362,18 +362,18 @@ trigger:
- kind: InvokeAzureAgent
id: question_wFJ123
displayName: Get New Facts Prompt
conversationId: =Topic.InternalConversationId
conversationId: =Local.InternalConversationId
agent:
name: =Env.FOUNDRY_AGENT_RESEARCHANALYST
output:
messages: Topic.TaskFacts
messages: Local.TaskFacts
input:
messages: |-
=[
UserMessage(
"As a reminder, we are working to solve the following task:
" & Topic.InputTask)
" & Local.InputTask)
]
additionalInstructions: |-
It's clear we aren't making as much progress as we would like, but we may have learned something new.
@@ -384,7 +384,7 @@ trigger:
Here is the old fact sheet:
{Topic.TaskFacts}
{Local.TaskFacts}
- kind: SendActivity
id: sendActivity_dsBaJU
@@ -393,11 +393,11 @@ trigger:
- kind: InvokeAzureAgent
id: question_uEJ456
displayName: Create new Plan Prompt
conversationId: =Topic.InternalConversationId
conversationId: =Local.InternalConversationId
agent:
name: =Env.FOUNDRY_AGENT_RESEARCHMANAGER
output:
messages: Topic.Plan
messages: Local.Plan
input:
additionalInstructions: |-
Please briefly explain what went wrong on this last run (the root cause of the failure),
@@ -405,47 +405,47 @@ trigger:
As before, the new plan should be concise, be expressed in bullet-point form, and consider the following team composition
(do not involve any other outside people since we cannot contact anyone else):
{Topic.TeamDescription}
{Local.TeamDescription}
- kind: SetVariable
id: setVariable_jW7tmM
displayName: Set Plan as Context
variable: Topic.TaskInstructions
variable: Local.TaskInstructions
value: |-
="# TASK
Address the following user request:
" & Topic.InputTask & "
" & Local.InputTask & "
# TEAM
Use the following team to answer this request:
" & Topic.TeamDescription & "
" & Local.TeamDescription & "
# FACTS
Consider this initial fact sheet:
" & Topic.TaskFacts.Text & "
" & Local.TaskFacts.Text & "
# PLAN
Here is the plan to follow as best as possible:
" & Topic.Plan.Text
" & Local.Plan.Text
- kind: SetVariable
id: setVariable_6J2snP
displayName: Reset Stall count
variable: Topic.StallCount
variable: Local.StallCount
value: 0
- kind: SetVariable
id: setVariable_S6HCgh
displayName: Increase Restart count
variable: Topic.RestartCount
value: =Topic.RestartCount + 1
variable: Local.RestartCount
value: =Local.RestartCount + 1
- kind: GotoAction
id: goto_LzfJ8u
@@ -455,25 +455,25 @@ trigger:
- kind: SendActivity
id: sendActivity_L7ooQO
activity: |-
({Topic.TypedProgressLedger.next_speaker.reason})
({Local.TypedProgressLedger.next_speaker.reason})
{Topic.TypedProgressLedger.next_speaker.answer} - {Topic.TypedProgressLedger.instruction_or_question.answer}
{Local.TypedProgressLedger.next_speaker.answer} - {Local.TypedProgressLedger.instruction_or_question.answer}
- kind: SetVariable
id: setVariable_L7ooQO
variable: Topic.StallCount
variable: Local.StallCount
value: 0
- kind: SetVariable
id: setVariable_nxN1mE
variable: Topic.NextSpeaker
value: =Search(Topic.AvailableAgents, Topic.TypedProgressLedger.next_speaker.answer, name)
variable: Local.NextSpeaker
value: =Search(Local.AvailableAgents, Local.TypedProgressLedger.next_speaker.answer, name)
- kind: ConditionGroup
id: conditionGroup_QFPiF5
conditions:
- id: conditionItem_GmigcU
condition: =CountRows(Topic.NextSpeaker) = 1
condition: =CountRows(Local.NextSpeaker) = 1
displayName: If next Agent tool Exists
actions:
@@ -482,23 +482,23 @@ trigger:
displayName: Progress Ledger Prompt
conversationId: =System.ConversationId
agent:
name: =First(Topic.NextSpeaker).agentid
name: =First(Local.NextSpeaker).agentid
output:
messages: Topic.AgentResponse
messages: Local.AgentResponse
input:
messages: =[UserMessage(Topic.SeedTask)]
messages: =[UserMessage(Local.SeedTask)]
additionalInstructions: |-
{Topic.TypedProgressLedger.instruction_or_question.answer}
{Local.TypedProgressLedger.instruction_or_question.answer}
- kind: SetVariable
id: setVariable_XzNrdM
variable: Topic.AgentResponseText
value: =Topic.AgentResponse.Text
variable: Local.AgentResponseText
value: =Local.AgentResponse.Text
- kind: ResetVariable
id: setVariable_8eIx2A
displayName: Clear seed task
variable: Topic.SeedTask
variable: Local.SeedTask
elseActions:
- kind: SendActivity
@@ -508,8 +508,8 @@ trigger:
- kind: SetVariable
id: setVariable_BhcsI7
displayName: Increase stall count
variable: Topic.StallCount
value: =Topic.StallCount + 1
variable: Local.StallCount
value: =Local.StallCount + 1
- kind: GotoAction
id: goto_76Hne8
+6 -6
View File
@@ -14,14 +14,14 @@ trigger:
# Capture original input
- kind: SetVariable
id: set_project
variable: Topic.OriginalInput
variable: Local.OriginalInput
value: =System.LastMessage.Text
# Request input from user
- kind: Question
id: question_confirm
alwaysPrompt: false
property: Topic.ConfirmedInput
property: Local.ConfirmedInput
prompt:
kind: Message
text:
@@ -35,14 +35,14 @@ trigger:
conditions:
# Didn't match
- condition: =Topic.OriginalInput <> Topic.ConfirmedInput
- condition: =Local.OriginalInput <> Local.ConfirmedInput
id: check_confirm
actions:
- kind: SendActivity
id: sendActivity_mismatch
activity: |-
"{Topic.ConfirmedInput}" does not match the original input of "{Topic.OriginalInput}". Please try again.
"{Local.ConfirmedInput}" does not match the original input of "{Local.OriginalInput}". Please try again.
- kind: GotoAction
id: goto_again
@@ -54,10 +54,10 @@ trigger:
id: sendActivity_confirmed
activity: |-
You entered:
{Topic.OriginalInput}
{Local.OriginalInput}
Confirmed input:
{Topic.ConfirmedInput}
{Local.ConfirmedInput}
+8 -8
View File
@@ -33,7 +33,7 @@ trigger:
- kind: SetVariable
id: set_project
variable: Topic.Project
variable: Local.Project
value: =System.LastMessage.Text
- kind: InvokeAzureAgent
@@ -42,11 +42,11 @@ trigger:
agent:
name: =Env.FOUNDRY_AGENT_STUDENT
input:
messages: =[UserMessage(Topic.Project)]
messages: =[UserMessage(Local.Project)]
- kind: ResetVariable
id: reset_project
variable: Topic.Project
variable: Local.Project
- kind: InvokeAzureAgent
id: question_teacher
@@ -54,18 +54,18 @@ trigger:
agent:
name: =Env.FOUNDRY_AGENT_TEACHER
output:
messages: Topic.TeacherResponse
messages: Local.TeacherResponse
- kind: SetVariable
id: set_count_increment
variable: Topic.TurnCount
value: =Topic.TurnCount + 1
variable: Local.TurnCount
value: =Local.TurnCount + 1
- kind: ConditionGroup
id: check_completion
conditions:
- condition: =!IsBlank(Find("CONGRATULATIONS", Upper(Topic.TeacherResponse.Text)))
- condition: =!IsBlank(Find("CONGRATULATIONS", Upper(Local.TeacherResponse.Text)))
id: check_turn_done
actions:
@@ -73,7 +73,7 @@ trigger:
id: sendActivity_done
activity: GOLD STAR!
- condition: =Topic.TurnCount < 4
- condition: =Local.TurnCount < 4
id: check_turn_count
actions: