diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs
index 2c0aa15ed..3c93976bd 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs
@@ -3,7 +3,8 @@ namespace BotSharp.Abstraction.Routing;
public interface IRoutingContext
{
string GetCurrentAgentId();
- string PreviousAgentId();
+ string FirstGoalAgentId();
+ bool ContainsAgentId(string agentId);
string OriginAgentId { get; }
string ConversationId { get; }
string MessageId { get; }
@@ -13,6 +14,7 @@ public interface IRoutingContext
int AgentCount { get; }
void Push(string agentId, string? reason = null);
void Pop(string? reason = null);
+ void PopTo(string agentId, string reason);
void Replace(string agentId, string? reason = null);
void Empty(string? reason = null);
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
index 7df5fa02a..eb21fb31c 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
@@ -14,6 +14,13 @@ public class AgentPlugin : IBotSharpPlugin
public SettingsMeta Settings =>
new SettingsMeta("Agent");
+ public string[] AgentIds => new string[]
+ {
+ "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
+ "01e2fc5c-2c89-4ec7-8470-7688608b496c",
+ "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b"
+ };
+
public object GetNewSettingsInstance() =>
new AgentSettings();
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index ece7daa7d..873fa93ae 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -46,6 +46,9 @@
+
+
+
@@ -67,6 +70,15 @@
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs
new file mode 100644
index 000000000..d0c26be03
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs
@@ -0,0 +1,29 @@
+using BotSharp.Abstraction.Functions;
+
+namespace BotSharp.Core.Routing.Functions;
+
+public class HumanInterventionNeededFn : IFunctionCallback
+{
+ public string Name => "human_intervention_needed";
+
+ private readonly IServiceProvider _services;
+
+ public HumanInterventionNeededFn(IServiceProvider services)
+ {
+ _services = services;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var hooks = _services.GetServices()
+ .OrderBy(x => x.Priority)
+ .ToList();
+
+ foreach (var hook in hooks)
+ {
+ await hook.OnHumanInterventionNeeded(message);
+ }
+
+ return true;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
index 8221cfb5d..2450a6fc0 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
@@ -51,7 +51,7 @@ public async Task Execute(RoleDialogModel message)
var originalAgent = db.GetAgents(filter).FirstOrDefault();
if (originalAgent != null)
{
- _context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " & is corrected" : "")}");
+ _context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " " + originalAgent.Name + " & is corrected" : "")}");
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs
deleted file mode 100644
index 4aca2c3a8..000000000
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using BotSharp.Abstraction.Routing.Settings;
-
-namespace BotSharp.Core.Routing.Handlers;
-
-public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandler
-{
- public string Name => "human_intervention_needed";
-
- public string Description => "Reach out to human customer service.";
-
- public List Parameters => new List
- {
- new ParameterPropertyDef("reason", "why need customer service"),
- new ParameterPropertyDef("summary", "the whole conversation summary with important information"),
- new ParameterPropertyDef("response", "asking user whether to connect with customer service representative")
- };
-
- public HumanInterventionNeededHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
- : base(services, logger, settings)
- {
-
- }
-
- public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
- {
- var response = RoleDialogModel.From(message,
- role: AgentRole.Assistant,
- content: inst.Response);
-
- _dialogs.Add(response);
-
- var hooks = _services.GetServices()
- .OrderBy(x => x.Priority)
- .ToList();
-
- foreach (var hook in hooks)
- {
- await hook.OnHumanInterventionNeeded(response);
- }
-
- return true;
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
index 87e55840a..4d8eba43d 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Routing.Settings;
+using BotSharp.Abstraction.Utilities;
namespace BotSharp.Core.Routing;
@@ -137,7 +138,18 @@ await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason)
}
}
- public string PreviousAgentId()
+ public void PopTo(string agentId, string reason)
+ {
+ var currentAgentId = GetCurrentAgentId();
+ while (!string.IsNullOrEmpty(currentAgentId) &&
+ currentAgentId != agentId)
+ {
+ Pop(reason);
+ currentAgentId = GetCurrentAgentId();
+ }
+ }
+
+ public string FirstGoalAgentId()
{
if (_stack.Count == 1)
{
@@ -151,6 +163,11 @@ public string PreviousAgentId()
return string.Empty;
}
+ public bool ContainsAgentId(string agentId)
+ {
+ return _stack.ToArray().Contains(agentId);
+ }
+
public void Replace(string agentId, string? reason = null)
{
var fromAgent = agentId;
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/agent.json
new file mode 100644
index 000000000..d32e46800
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/agent.json
@@ -0,0 +1,11 @@
+{
+ "id": "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b",
+ "name": "Human Support",
+ "description": "Reach out to human customer service representative.",
+ "type": "task",
+ "createdDateTime": "2024-04-22T10:00:00Z",
+ "updatedDateTime": "2024-04-22T10:00:00Z",
+ "disabled": false,
+ "isPublic": true,
+ "profiles": [ "human" ]
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/functions.json b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/functions.json
new file mode 100644
index 000000000..240f5b7c3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/functions.json
@@ -0,0 +1,20 @@
+[
+ {
+ "name": "human_intervention_needed",
+ "description": "If user wants to speak to human customer service.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "reason": {
+ "type": "string",
+ "description": "why customer needs customer service."
+ },
+ "summary": {
+ "type": "string",
+ "description": "the whole conversation summary with important information"
+ }
+ },
+ "required": [ "reason", "summary" ]
+ }
+ }
+]
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instruction.liquid
new file mode 100644
index 000000000..3b1aab426
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instruction.liquid
@@ -0,0 +1,2 @@
+You are a human customer service connection program.
+When other AI customer service cannot solve user problems, you know how to call the API to transfer users to human customer service for answers.
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid
index 3a332350a..f7388be6c 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid
@@ -10,5 +10,3 @@ Expected user goal agent is {{ expected_user_goal_agent }}.
{%- else -%}
User goal agent is inferred based on user initial request.
{%- endif %}
-If user wants to speak to human customer service, use function human_intervention_needed.
-If user wants to or is processing with a specific task that can be handled by agents, respond in appropriate output format defined to let proper agent to handle the task.