diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs index e2a56817..bd71009b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs @@ -25,6 +25,10 @@ public class FunctionDef [JsonPropertyName("parameters")] public FunctionParametersDef Parameters { get; set; } = new FunctionParametersDef(); + [JsonPropertyName("output")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Output { get; set; } + public override string ToString() { return $"{Name}: {Description}"; diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs index bec44bc4..7bfd9352 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs @@ -101,8 +101,8 @@ public partial class RoutingService Context.SetDialogs(dialogs); // Send to Next LLM - var agentId = routing.Context.GetCurrentAgentId(); - await InvokeAgent(agentId, dialogs); + var curAgentId = routing.Context.GetCurrentAgentId(); + await InvokeAgent(curAgentId, dialogs); } } else diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs index fb074dfc..aaa81694 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs @@ -1,4 +1,7 @@ using BotSharp.Abstraction.Functions; +using BotSharp.Abstraction.Options; +using BotSharp.Abstraction.Templating; + namespace BotSharp.Core.Routing; public partial class RoutingService @@ -8,6 +11,12 @@ public partial class RoutingService var function = _services.GetServices().FirstOrDefault(x => x.Name == name); if (function == null) { + var executed = await InvokeDummyFunction(name, message); + if (executed) + { + return true; + } + message.StopCompletion = true; message.Content = $"Can't find function implementation of {name}."; _logger.LogError(message.Content); @@ -87,4 +96,54 @@ public partial class RoutingService return result; } + + private async Task InvokeDummyFunction(string functionName, RoleDialogModel message) + { + if (string.IsNullOrEmpty(message.CurrentAgentId)) + { + return false; + } + + var agentService = _services.GetRequiredService(); + var agent = await agentService.GetAgent(message.CurrentAgentId); + var found = agent?.Functions?.FirstOrDefault(x => x.Name == functionName); + if (string.IsNullOrWhiteSpace(found?.Output)) + { + return false; + } + + var clonedMessage = RoleDialogModel.From(message); + clonedMessage.FunctionName = functionName; + clonedMessage.Indication = "Running"; + + var hooks = _services + .GetRequiredService() + .HooksOrderByPriority; + + foreach (var hook in hooks) + { + await hook.OnFunctionExecuting(clonedMessage); + } + + var render = _services.GetRequiredService(); + var state = _services.GetRequiredService(); + var options = _services.GetRequiredService(); + + var dict = new Dictionary(); + foreach (var item in state.GetStates()) + { + dict[item.Key] = item.Value; + } + + var text = render.Render(found.Output, dict); + message.Content = text; + clonedMessage.Content = text; + + foreach (var hook in hooks) + { + await hook.OnFunctionExecuted(clonedMessage); + } + + return true; + } } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs index f274eb0c..8ad69be5 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs @@ -12,6 +12,7 @@ public class FunctionDefMongoElement public string? VisibilityExpression { get; set; } public string? Impact { get; set; } public FunctionParametersDefMongoElement Parameters { get; set; } = new(); + public string? Output { get; set; } public static FunctionDefMongoElement ToMongoElement(FunctionDef function) { @@ -27,7 +28,8 @@ public class FunctionDefMongoElement Type = function.Parameters.Type, Properties = JsonSerializer.Serialize(function.Parameters.Properties), Required = function.Parameters.Required, - } + }, + Output = function.Output }; } @@ -45,7 +47,8 @@ public class FunctionDefMongoElement Type = function.Parameters.Type, Properties = JsonSerializer.Deserialize(function.Parameters.Properties.IfNullOrEmptyAs("{}")), Required = function.Parameters.Required, - } + }, + Output = function.Output }; } }