diff --git a/libraries/Microsoft.Bot.Builder.LanguageGeneration/Evaluator.cs b/libraries/Microsoft.Bot.Builder.LanguageGeneration/Evaluator.cs index 91fa17258c..bb9e210656 100644 --- a/libraries/Microsoft.Bot.Builder.LanguageGeneration/Evaluator.cs +++ b/libraries/Microsoft.Bot.Builder.LanguageGeneration/Evaluator.cs @@ -287,7 +287,7 @@ public object ConstructScope(string inputTemplateName, List args) } var parameters = TemplateMap[templateName].Parameters; - var currentScope = _evaluationTargetStack.Count > 0 ? CurrentTarget().Scope : new CustomizedMemory(null); + var currentScope = CurrentTarget().Scope; if (args.Count == 0) { diff --git a/libraries/Microsoft.Bot.Builder.LanguageGeneration/Templates.cs b/libraries/Microsoft.Bot.Builder.LanguageGeneration/Templates.cs index b30740f532..91105cbe0e 100644 --- a/libraries/Microsoft.Bot.Builder.LanguageGeneration/Templates.cs +++ b/libraries/Microsoft.Bot.Builder.LanguageGeneration/Templates.cs @@ -427,7 +427,34 @@ private Templates InjectToExpressionFunction() if (curTemplates.Any(u => u.Name == templateName)) { var newGlobalName = $"{curTemplates.Namespace}.{templateName}"; - Expression.Functions.Add(newGlobalName, new ExpressionEvaluator(newGlobalName, FunctionUtils.Apply(GlobalTemplateFunction(templateName)), ReturnType.Object)); + Expression.Functions.Add(newGlobalName, new ExpressionEvaluator( + newGlobalName, + (expression, state, options) => + { + object result = null; + var evaluator = new Evaluator(AllTemplates.ToList(), ExpressionParser, LgOptions); + var (args, error) = FunctionUtils.EvaluateChildren(expression, state, options); + if (error == null) + { + var parameters = evaluator.TemplateMap[templateName].Parameters; + var newScope = parameters.Zip(args, (k, v) => new { k, v }) + .ToDictionary(x => x.k, x => x.v); + var scope = new CustomizedMemory(state, new SimpleObjectMemory(newScope)); + try + { + result = evaluator.EvaluateTemplate(templateName, scope); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception err) +#pragma warning restore CA1031 // Do not catch general exception types + { + error = err.Message; + } + } + + return (result, error); + }, + ReturnType.Object)); } } } @@ -622,13 +649,5 @@ private IList GetGlobalFunctionTable(IList options) return result; } - - private Func, object> GlobalTemplateFunction(string templateName) - => (IReadOnlyList args) => - { - var evaluator = new Evaluator(AllTemplates.ToList(), ExpressionParser, LgOptions); - var newScope = evaluator.ConstructScope(templateName, args.ToList()); - return evaluator.EvaluateTemplate(templateName, newScope); - }; } } diff --git a/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/Fallback/inject.dialog b/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/Fallback/inject.dialog index dd7046b203..b3860aa3c8 100644 --- a/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/Fallback/inject.dialog +++ b/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/Fallback/inject.dialog @@ -11,6 +11,17 @@ "property": "user.message", "value": "=foo.GetMessage()" }, + { + "$kind": "Microsoft.SetProperty", + "property": "user.name", + "value": "jonathan" + }, + { + "$kind": "Microsoft.SetProperty", + "property": "user.date", + "value": "2003-03-20" + }, + { "$kind": "Microsoft.SetProperty", "property": "user.tasks", @@ -28,8 +39,19 @@ { "$kind": "Microsoft.SendActivity", "activity": "${user.message}" + }, + { + "$kind": "Microsoft.SendActivity", + "activity": "${foo.WelcomeUser()}" + }, + { + "$kind": "Microsoft.SendActivity", + "activity": "${foo.UserDataConcat(user.date)}" + }, + { + "$kind": "Microsoft.SendActivity", + "activity": "${foo.ShowTasks(foo.GetList(user.tasks))}" } - ] } ] diff --git a/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/LGGeneratorTests.cs b/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/LGGeneratorTests.cs index 53ad4675a0..df560e41ea 100644 --- a/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/LGGeneratorTests.cs +++ b/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/LGGeneratorTests.cs @@ -420,6 +420,9 @@ await CreateFlow(async (turnContext, cancellationToken) => .Send("hello") .AssertReply("[{\"Id\":0,\"Topic\":\"car\"},{\"Id\":1,\"Topic\":\"washing\"},{\"Id\":2,\"Topic\":\"food\"},{\"Id\":3,\"Topic\":\"laundry\"}]") .AssertReply("This is an injected message") + .AssertReply("Hi Jonathan") + .AssertReply("Jonathan : 2003-03-20") + .AssertReply("Jonathan, your tasks: car, washing, food and laundry") .StartTestAsync(); } diff --git a/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/lg/inject.lg b/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/lg/inject.lg index ff4ae23e79..6924a1e2af 100644 --- a/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/lg/inject.lg +++ b/tests/Microsoft.Bot.Builder.Dialogs.Adaptive.Templates.Tests/lg/inject.lg @@ -1,6 +1,6 @@ > !# @strict = false > !# @namespace = foo -> !# @Exports = GetList, Convert, GetProperty, GetMessage +> !# @Exports = GetList, Convert, GetProperty, GetMessage, UserDataConcat, WelcomeUser, ShowTasks # Convert(index, value) @@ -13,4 +13,15 @@ -user.tasks #GetMessage -- This is an injected message \ No newline at end of file +- This is an injected message + +> Use both global and local memory +#UserDataConcat(date) +- ${sentenceCase(user.name)} : ${date} + +> Use global memory +#WelcomeUser +- Hi ${sentenceCase(user.name)} + +# ShowTasks(tasks) +- ${sentenceCase(user.name)}, your tasks: ${join(foreach(tasks, task, task.value), ', ', ' and ')} \ No newline at end of file diff --git a/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/Examples/InjectionTest/inject.lg b/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/Examples/InjectionTest/inject.lg index 66d423934a..73ee656e27 100644 --- a/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/Examples/InjectionTest/inject.lg +++ b/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/Examples/InjectionTest/inject.lg @@ -1,11 +1,20 @@ > !# @strict = false -> !# @Namespace = foo -> !# @Exports = bar, cool +> !# @Namespace = general +> !# @Exports = sumAll, cool, greeting, addTwoNum, yolo [import](common.lg) -#bar() +#sumAll() - ${add(1,2)} #cool(a) -- ${add(1,a)} \ No newline at end of file +- ${add(1,a)} + +#greeting +- hi ${name} + +#addTwoNum(a,b) +- ${a + b} + +# yolo(a, b) +- ${name} have ${a + b} cookies! \ No newline at end of file diff --git a/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/TemplatesTest.cs b/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/TemplatesTest.cs index 83bdf13a86..1d3142c000 100644 --- a/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/TemplatesTest.cs +++ b/tests/Microsoft.Bot.Builder.LanguageGeneration.Tests/TemplatesTest.cs @@ -1481,12 +1481,33 @@ public void TestCustomFunction2() public void TestInjectLG() { var templates = Templates.ParseFile(GetExampleFilePath("./InjectionTest/inject.lg")); - - var (evaled, error) = Expression.Parse("foo.bar()").TryEvaluate(null); - + + var (evaled, error) = Expression.Parse("general.greeting()").TryEvaluate(new { name = "Alice" }); + Assert.Equal("hi Alice", evaled.ToString()); + + var memory1 = new StackedMemory(); + memory1.Push(new SimpleObjectMemory(new { name = "Alice" })); + memory1.Push(new CustomizedMemory(new { name = "Bob" })); + (evaled, error) = Expression.Parse("general.greeting()").TryEvaluate(memory1); + Assert.Equal("hi Bob", evaled.ToString()); + + (evaled, error) = Expression.Parse("general.yolo(8, 7)").TryEvaluate(new { name = "Alice" }); + Assert.Equal("Alice have 15 cookies!", evaled.ToString()); + + var memory2 = new StackedMemory(); + memory2.Push(new SimpleObjectMemory(new { name = "Alice" })); + memory2.Push(new CustomizedMemory(new { name = "Bob" })); + (evaled, error) = Expression.Parse("general.yolo(12, 12)").TryEvaluate(memory2); + Assert.Equal("Bob have 24 cookies!", evaled.ToString()); + + (evaled, error) = Expression.Parse("general.addTwoNum(5,6)").TryEvaluate(new { a = 3, b = 1 }); + Assert.Equal("11", evaled.ToString()); + + (evaled, error) = Expression.Parse("general.sumAll()").TryEvaluate(null); + Assert.Equal("3", evaled.ToString()); - (evaled, error) = Expression.Parse("foo.cool(2)").TryEvaluate(null); + (evaled, error) = Expression.Parse("general.cool(2)").TryEvaluate(null); Assert.Equal("3", evaled.ToString()); (evaled, error) = Expression.Parse("common.looking()").TryEvaluate(null);