diff --git a/docs/agent/intro.md b/docs/agent/intro.md
index 7507ef2e..7e750ce3 100644
--- a/docs/agent/intro.md
+++ b/docs/agent/intro.md
@@ -2,7 +2,7 @@
An agent helps you process user sentences (unstructure data) into structure data that you can use to return an appropriate response.
-Agent is a collection that contains prompt words and function Json Schema definitions, few-shot examples and knowledge base data. You can create multiple different Agents to perform specific operations in specific domains. BotSharp has built-in maintenance for Agents, including creating, updating and deleting, importing and exporting.
+Agent is a collection that contains prompt words and function Json Schema definitions, few-shot examples and knowledge base data. You can create multiple different Agents to perform specific operations in specific domains. BotSharp has built-in maintenance for Agents, including creating, updating and deleting, importing and exporting. Agents are divided into `task agents`, `routing (non-task) agents`, `evaluating agents` and `static agents`. Business domain agents belong to task agents, and routers belong to non-task agents, static agents don't have capabilities to interact with external environment.
## My Agent
After creating the platform account, you can start to enter the steps of creating the Agent.
diff --git a/docs/architecture/routing.md b/docs/architecture/routing.md
index a4bbb6ea..8732cd59 100644
--- a/docs/architecture/routing.md
+++ b/docs/architecture/routing.md
@@ -14,4 +14,8 @@ For simple questions raised by users, the ordinary routing function can already

-For more **Routing** related information, please go to [Agent Routing](../agent/router.md).
\ No newline at end of file
+For more **Routing** related information, please go to [Agent Routing](../agent/router.md).
+
+## Profile
+
+There is an array field called `Profile` in the Agent data model, which is used to store the current profiles. When this attribute is set in the `Router`, only matching Task Agents can be included in the routing candidate Agents list, which means that the Task Agent also To set the same profile name. Profiles allows you to enter multiple profiles, and the system will automatically combine them for processing.
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
index 669ebaba..0fdeffe3 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
@@ -7,7 +7,7 @@ public enum AgentField
Description,
IsPublic,
Disabled,
- AllowRouting,
+ Type,
Profiles,
RoutingRule,
Instruction,
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs
new file mode 100644
index 00000000..17689407
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs
@@ -0,0 +1,22 @@
+namespace BotSharp.Abstraction.Agents.Enums;
+
+public class AgentType
+{
+ ///
+ /// Routing Agent
+ ///
+ public const string Routing = "routing";
+
+ public const string Evaluating = "evaluating";
+
+ ///
+ /// Routable task agent with capability of interaction with external environment
+ ///
+ public const string Task = "task";
+
+ ///
+ /// Agent that cannot use external tools
+ ///
+ public const string Static = "static";
+}
+
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 76019e47..5f3b1b87 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -10,7 +10,7 @@ public interface IAgentService
{
Task CreateAgent(Agent agent);
Task RefreshAgents();
- Task> GetAgents(AgentFilter filter);
+ Task> GetAgents(AgentFilter filter);
///
/// Load agent configurations and trigger hooks
@@ -29,7 +29,7 @@ public interface IAgentService
///
/// Original agent information
Task GetAgent(string id);
-
+
Task DeleteAgent(string id);
Task UpdateAgent(Agent agent, AgentField updateField);
Task UpdateAgentFromFile(string id);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 1280c865..a36ccc26 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -9,6 +9,10 @@ public class Agent
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
+ ///
+ /// Agent Type
+ ///
+ public string Type { get; set; } = AgentType.Task;
public DateTime CreatedDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
@@ -16,7 +20,8 @@ public class Agent
/// Default LLM settings
///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public AgentLlmConfig? LlmConfig { get; set; }
+ public AgentLlmConfig LlmConfig { get; set; }
+ = new AgentLlmConfig();
///
/// Instruction
@@ -58,7 +63,7 @@ public class Agent
public bool IsPublic { get; set; }
[JsonIgnore]
- public bool IsRouter { get; set; }
+ public bool IsHost { get; set; }
[JsonIgnore]
public PluginDef Plugin { get; set; }
@@ -66,11 +71,6 @@ public class Agent
[JsonIgnore]
public bool Installed => Plugin.Enabled;
- ///
- /// Allow to be routed
- ///
- public bool AllowRouting { get; set; }
-
///
/// Default is True, user will enable this by installing appropriate plugin.
///
@@ -104,6 +104,7 @@ public class Agent
Id = agent.Id,
Name = agent.Name,
Description = agent.Description,
+ Type = agent.Type,
Instruction = agent.Instruction,
Functions = agent.Functions,
Responses = agent.Responses,
@@ -111,7 +112,6 @@ public class Agent
Knowledges = agent.Knowledges,
IsPublic = agent.IsPublic,
Disabled = agent.Disabled,
- AllowRouting = agent.AllowRouting,
Profiles = agent.Profiles,
RoutingRules = agent.RoutingRules,
LlmConfig = agent.LlmConfig,
@@ -180,9 +180,9 @@ public class Agent
return this;
}
- public Agent SetAllowRouting(bool allowRouting)
+ public Agent SetAgentType(string type)
{
- AllowRouting = allowRouting;
+ Type = type;
return this;
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
index e902efc5..8025c2b8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
@@ -21,4 +21,7 @@ public class AgentLlmConfig
[JsonPropertyName("model")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Model { get; set; }
+
+ [JsonPropertyName("max_recursion_depth")]
+ public int MaxRecursionDepth { get; set; } = 3;
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationStateLogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationStateLogModel.cs
new file mode 100644
index 00000000..de80b485
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationStateLogModel.cs
@@ -0,0 +1,11 @@
+namespace BotSharp.Abstraction.Conversations.Models;
+
+public class ConversationStateLogModel
+{
+ [JsonPropertyName("conversation_id")]
+ public string ConvsersationId { get; set; }
+ [JsonPropertyName("states")]
+ public string States { get; set; }
+ [JsonPropertyName("created_at")]
+ public DateTime CreateTime { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
index beeaf629..e9b40722 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
@@ -53,12 +53,6 @@ public class RoleDialogModel : ITrackableMessage
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public bool StopCompletion { get; set; }
- ///
- /// Router routed to a wrong agent.
- /// Set this flag as True will force router to re-route current request to a new agent.
- ///
- public bool UnmatchedAgent { get; set; }
-
public FunctionCallFromLlm Instruction { get; set; }
private RoleDialogModel()
diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs
index d4e69e2a..975a17d6 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs
@@ -5,7 +5,7 @@ namespace BotSharp.Abstraction.Functions.Models;
public class FunctionParametersDef
{
[JsonPropertyName("type")]
- public string Type { get; set; } = "string";
+ public string Type { get; set; } = "object";
///
/// ParameterPropertyDef
diff --git a/src/Infrastructure/BotSharp.Abstraction/Loggers/Models/StreamingLogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Loggers/Models/StreamingLogModel.cs
index d361bf59..51941138 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Loggers/Models/StreamingLogModel.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Loggers/Models/StreamingLogModel.cs
@@ -4,6 +4,8 @@ public class StreamingLogModel
{
[JsonPropertyName("conversation_id")]
public string ConversationId { get; set; }
+ [JsonPropertyName("name")]
+ public string? Name { get; set; }
[JsonPropertyName("content")]
public string Content { get; set; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentFilter.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentFilter.cs
index 1b4e232b..fb2bfed2 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentFilter.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentFilter.cs
@@ -2,12 +2,11 @@ namespace BotSharp.Abstraction.Repositories.Filters;
public class AgentFilter
{
+ public Pagination Pager { get; set; } = new Pagination();
public string? AgentName { get; set; }
public bool? Disabled { get; set; }
public bool? Installed { get; set; }
- public bool? AllowRouting { get; set; }
+ public string? Type { get; set; }
public bool? IsPublic { get; set; }
- public bool? IsRouter { get; set; }
- public bool? IsEvaluator { get; set; }
public List? AgentIds { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/RuleType.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/RuleType.cs
new file mode 100644
index 00000000..1d1913dd
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/RuleType.cs
@@ -0,0 +1,19 @@
+namespace BotSharp.Abstraction.Routing.Enums;
+
+public class RuleType
+{
+ ///
+ /// Fallback to redirect agent
+ ///
+ public const string Fallback = "fallback";
+
+ ///
+ /// Redirect to other agent if data validation failed
+ ///
+ public const string DataValidation = "data-validation";
+
+ ///
+ /// The planning approach name for next step
+ ///
+ public const string Planner = "planner";
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
index 17027652..a5369af9 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
@@ -5,10 +5,29 @@ namespace BotSharp.Abstraction.Routing;
public interface IRoutingService
{
Agent Router { get; }
- RoutingItem[] GetRoutingItems();
- RoutingRule[] GetRulesByName(string name);
+
+ ///
+ /// Get routable agents
+ ///
+ /// router's profile
+ ///
+ RoutableAgent[] GetRoutableAgents(List profiles);
+
+ ///
+ /// Get rules by agent name
+ ///
+ /// agent name
+ ///
+ RoutingRule[] GetRulesByAgentName(string name);
+
+ ///
+ /// Get rules by agent id
+ ///
+ /// agent id
+ ///
RoutingRule[] GetRulesByAgentId(string id);
- List GetHandlers();
+
+ List GetHandlers(Agent router);
void ResetRecursiveCounter();
Task InvokeAgent(string agentId, List dialogs);
Task InvokeFunction(string name, RoleDialogModel message);
@@ -20,5 +39,5 @@ public interface IRoutingService
///
///
///
- Task ExecuteDirectly(Agent agent, RoleDialogModel message);
+ Task InstructDirect(Agent agent, RoleDialogModel message);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs
similarity index 84%
rename from src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs
rename to src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs
index b08edfed..14fd6826 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs
@@ -2,7 +2,7 @@ using BotSharp.Abstraction.Functions.Models;
namespace BotSharp.Abstraction.Routing.Models;
-public class RoutingItem
+public class RoutableAgent
{
[JsonPropertyName("agent_id")]
public string AgentId { get; set; } = string.Empty;
@@ -13,6 +13,10 @@ public class RoutingItem
[JsonPropertyName("description")]
public string Description { get; set; } = string.Empty;
+ [JsonPropertyName("profiles")]
+ public List Profiles { get; set; }
+ = new List();
+
[JsonPropertyName("required_fields")]
public List RequiredFields { get; set; } = new List();
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs
index 9168b23f..d09658d8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs
@@ -1,12 +1,19 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Settings;
+using Microsoft.Extensions.DependencyInjection;
namespace BotSharp.Abstraction.Routing.Models;
public class RoutingContext
{
+ private readonly IServiceProvider _services;
private readonly RoutingSettings _setting;
- public RoutingContext(RoutingSettings setting)
+ private string[] _routerAgentIds;
+
+ public RoutingContext(IServiceProvider services, RoutingSettings setting)
{
+ _services = services;
_setting = setting;
}
@@ -22,7 +29,22 @@ public class RoutingContext
/// Agent that can handle user original goal.
///
public string OriginAgentId
- => _stack.Where(x => !_setting.AgentIds.Contains(x)).Last();
+ {
+ get
+ {
+ if (_routerAgentIds == null)
+ {
+ var agentService = _services.GetRequiredService();
+ _routerAgentIds = agentService.GetAgents(new AgentFilter
+ {
+ Type = AgentType.Routing
+ }).Result.Items
+ .Select(x => x.Id).ToArray();
+ }
+
+ return _stack.Where(x => !_routerAgentIds.Contains(x)).Last();
+ }
+ }
public bool IsEmpty => !_stack.Any();
public string GetCurrentAgentId()
@@ -46,6 +68,19 @@ public class RoutingContext
_stack.Pop();
}
+ public void Replace(string agentId)
+ {
+ if (_stack.Count == 0)
+ {
+ _stack.Push(agentId);
+ }
+ else if (_stack.Peek() != agentId)
+ {
+ _stack.Pop();
+ _stack.Push(agentId);
+ }
+ }
+
public void Empty()
{
_stack.Clear();
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs
index 88835216..b652ced1 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs
@@ -1,3 +1,5 @@
+using BotSharp.Abstraction.Routing.Enums;
+
namespace BotSharp.Abstraction.Routing.Models;
public class RoutingRule
@@ -8,12 +10,15 @@ public class RoutingRule
[JsonIgnore]
public string AgentName { get; set; }
+ public string Type { get; set; } = RuleType.DataValidation;
+
public string Field { get; set; }
public string Description { get; set; }
+
///
/// Field type: string, number, object
///
- public string Type { get; set; } = "string";
+ public string FieldType { get; set; } = "string";
public bool Required { get; set; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
index eb7f099a..6b7ef62c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
@@ -2,10 +2,4 @@ namespace BotSharp.Abstraction.Routing.Settings;
public class RoutingSettings
{
- ///
- /// Router Agent Id
- ///
- public string[] AgentIds { get; set; } = new string[0];
-
- public string Planner { get; set; } = string.Empty;
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
index 772c21f9..ce74d7c4 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
@@ -33,7 +33,7 @@ public partial class AgentService
.SetDescription(foundAgent.Description)
.SetIsPublic(foundAgent.IsPublic)
.SetDisabled(foundAgent.Disabled)
- .SetAllowRouting(foundAgent.AllowRouting)
+ .SetAgentType(foundAgent.Type)
.SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction)
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
index aba053a0..15be18f9 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
@@ -9,7 +9,7 @@ public partial class AgentService
#if !DEBUG
[MemoryCache(10 * 60)]
#endif
- public async Task> GetAgents(AgentFilter filter)
+ public async Task> GetAgents(AgentFilter filter)
{
var agents = _db.GetAgents(filter);
@@ -17,13 +17,23 @@ public partial class AgentService
var routeSetting = _services.GetRequiredService();
foreach (var agent in agents)
{
- agent.IsRouter = routeSetting.AgentIds.Contains(agent.Id);
agent.Plugin = GetPlugin(agent.Id);
}
- agents = agents.Where(x => x.Installed).ToList();
+ // Set IsHost
+ var agentSetting = _services.GetRequiredService();
+ foreach (var agent in agents)
+ {
+ agent.IsHost = agentSetting.HostAgentId == agent.Id;
+ }
- return agents;
+ agents = agents.Where(x => x.Installed).ToList();
+ var pager = filter?.Pager ?? new Pagination();
+ return new PagedItems
+ {
+ Items = agents.Skip(pager.Offset).Take(pager.Size),
+ Count = agents.Count()
+ };
}
#if !DEBUG
@@ -47,9 +57,6 @@ public partial class AgentService
profile.LlmConfig.IsInherit = true;
}
- // Set IsRouter
- var routeSetting = _services.GetRequiredService();
- profile.IsRouter = routeSetting.AgentIds.Contains(profile.Id);
profile.Plugin = GetPlugin(profile.Id);
return profile;
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
index 459cace4..4577af6d 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
@@ -19,7 +19,7 @@ public partial class AgentService
record.Description = agent.Description ?? string.Empty;
record.IsPublic = agent.IsPublic;
record.Disabled = agent.Disabled;
- record.AllowRouting = agent.AllowRouting;
+ record.Type = agent.Type;
record.Profiles = agent.Profiles ?? new List();
record.RoutingRules = agent.RoutingRules ?? new List();
record.Instruction = agent.Instruction ?? string.Empty;
@@ -60,7 +60,7 @@ public partial class AgentService
.SetDescription(foundAgent.Description)
.SetIsPublic(foundAgent.IsPublic)
.SetDisabled(foundAgent.Disabled)
- .SetAllowRouting(foundAgent.AllowRouting)
+ .SetAgentType(foundAgent.Type)
.SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction)
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index 2ad912dc..fadeacd1 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -50,8 +50,9 @@
-
-
+
+
+
@@ -70,10 +71,13 @@
PreserveNewest
-
+
PreserveNewest
-
+
+ PreserveNewest
+
+
PreserveNewest
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
index fd427562..92b840d7 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
@@ -59,9 +59,9 @@ public partial class ConversationService
var routing = _services.GetRequiredService();
var settings = _services.GetRequiredService();
- response = settings.AgentIds.Contains(agentId) ?
+ response = agent.Type == AgentType.Routing ?
await routing.InstructLoop(message) :
- await routing.ExecuteDirectly(agent, message);
+ await routing.InstructDirect(agent, message);
routing.ResetRecursiveCounter();
}
diff --git a/src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs b/src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs
index 206c22d5..8f4e0033 100644
--- a/src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs
+++ b/src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs
@@ -4,7 +4,6 @@ using BotSharp.Abstraction.Planning;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Models;
-using BotSharp.Abstraction.Routing.Settings;
using BotSharp.Abstraction.Templating;
namespace BotSharp.Core.Planning;
@@ -43,6 +42,7 @@ public class HFPlanner : IPlaner
{
new RoleDialogModel(AgentRole.User, next)
{
+ FunctionName = nameof(NaivePlanner),
MessageId = messageId
}
};
@@ -91,7 +91,7 @@ public class HFPlanner : IPlaner
private string GetNextStepPrompt(Agent router)
{
- var template = router.Templates.First(x => x.Name == "next_step_prompt.hf_planner").Content;
+ var template = router.Templates.First(x => x.Name == "planner_prompt.hf").Content;
var render = _services.GetRequiredService();
var prompt = render.Render(template, router.TemplateDict);
return prompt.Trim();
diff --git a/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs b/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
index 9ad95121..78112559 100644
--- a/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
+++ b/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
@@ -3,7 +3,6 @@ using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Planning;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Models;
-using BotSharp.Abstraction.Routing.Settings;
using BotSharp.Abstraction.Templating;
namespace BotSharp.Core.Planning;
@@ -49,6 +48,7 @@ public class NaivePlanner : IPlaner
{
new RoleDialogModel(AgentRole.User, next)
{
+ FunctionName = nameof(NaivePlanner),
MessageId = messageId
}
};
@@ -93,7 +93,7 @@ public class NaivePlanner : IPlaner
var unmatchedAgentId = context.GetCurrentAgentId();
// Exclude the wrong routed agent
- var agents = router.TemplateDict["routing_agents"] as RoutingItem[];
+ var agents = router.TemplateDict["routing_agents"] as RoutableAgent[];
router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray();
// Handover to Router;
@@ -108,7 +108,7 @@ public class NaivePlanner : IPlaner
private string GetNextStepPrompt(Agent router)
{
- var template = router.Templates.First(x => x.Name == "next_step_prompt").Content;
+ var template = router.Templates.First(x => x.Name == "planner_prompt.naive").Content;
var render = _services.GetRequiredService();
return render.Render(template, new Dictionary
@@ -125,8 +125,8 @@ public class NaivePlanner : IPlaner
var agentService = _services.GetRequiredService();
var agents = agentService.GetAgents(new AgentFilter
{
- AllowRouting = true
- }).Result;
+ Type = AgentType.Task
+ }).Result.Items.ToList();
var malformed = false;
// Sometimes it populate malformed Function in Agent name
diff --git a/src/Infrastructure/BotSharp.Core/Planning/SequentialPlanner.cs b/src/Infrastructure/BotSharp.Core/Planning/SequentialPlanner.cs
new file mode 100644
index 00000000..8f571266
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Planning/SequentialPlanner.cs
@@ -0,0 +1,113 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Planning;
+using BotSharp.Abstraction.Routing;
+using BotSharp.Abstraction.Routing.Models;
+using BotSharp.Abstraction.Templating;
+
+namespace BotSharp.Core.Planning;
+
+public class SequentialPlanner : IPlaner
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ public SequentialPlanner(IServiceProvider services, ILogger logger)
+ {
+ _services = services;
+ _logger = logger;
+ }
+
+ public async Task GetNextInstruction(Agent router, string messageId)
+ {
+ var next = GetNextStepPrompt(router);
+
+ var inst = new FunctionCallFromLlm();
+
+ // text completion
+ /*var agentService = _services.GetRequiredService();
+ var instruction = agentService.RenderedInstruction(router);
+ var content = $"{instruction}\r\n###\r\n{next}";
+ content = content + "\r\nResponse: ";
+ var completion = CompletionProvider.GetTextCompletion(_services);*/
+
+ // chat completion
+ var completion = CompletionProvider.GetChatCompletion(_services,
+ provider: router?.LlmConfig?.Provider,
+ model: router?.LlmConfig?.Model);
+
+ int retryCount = 0;
+ while (retryCount < 3)
+ {
+ string text = string.Empty;
+ try
+ {
+ // text completion
+ // text = await completion.GetCompletion(content, router.Id, messageId);
+ var dialogs = new List
+ {
+ new RoleDialogModel(AgentRole.User, next)
+ {
+ FunctionName = nameof(NaivePlanner),
+ MessageId = messageId
+ }
+ };
+ var response = await completion.GetChatCompletions(router, dialogs);
+
+ inst = response.Content.JsonContent();
+ break;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"{ex.Message}: {text}");
+ inst.Function = "response_to_user";
+ inst.Response = ex.Message;
+ inst.AgentName = "Router";
+ }
+ finally
+ {
+ retryCount++;
+ }
+ }
+
+ return inst;
+ }
+
+ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message)
+ {
+ // Set user content as Planner's question
+ message.FunctionName = inst.Function;
+ message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
+
+ return true;
+ }
+
+ public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message)
+ {
+ var context = _services.GetRequiredService();
+
+ if (message.StopCompletion)
+ {
+ context.Empty();
+ return false;
+ }
+
+ // Handover to Router;
+ context.Pop();
+
+ var routing = _services.GetRequiredService();
+ routing.ResetRecursiveCounter();
+
+ return true;
+ }
+
+ private string GetNextStepPrompt(Agent router)
+ {
+ var template = router.Templates.First(x => x.Name == "planner_prompt.sequential").Content;
+
+ var render = _services.GetRequiredService();
+ return render.Render(template, new Dictionary
+ {
+ });
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index c72711ff..b2476921 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -28,8 +28,8 @@ namespace BotSharp.Core.Repository
case AgentField.Disabled:
UpdateAgentDisabled(agent.Id, agent.Disabled);
break;
- case AgentField.AllowRouting:
- UpdateAgentAllowRouting(agent.Id, agent.AllowRouting);
+ case AgentField.Type:
+ UpdateAgentType(agent.Id, agent.Type);
break;
case AgentField.Profiles:
UpdateAgentProfiles(agent.Id, agent.Profiles);
@@ -112,12 +112,12 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json);
}
- private void UpdateAgentAllowRouting(string agentId, bool allowRouting)
+ private void UpdateAgentType(string agentId, string type)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return;
- agent.AllowRouting = allowRouting;
+ agent.Type = type;
agent.UpdatedDateTime = DateTime.UtcNow;
var json = JsonSerializer.Serialize(agent, _options);
File.WriteAllText(agentFile, json);
@@ -260,7 +260,7 @@ namespace BotSharp.Core.Repository
agent.Description = inputAgent.Description;
agent.IsPublic = inputAgent.IsPublic;
agent.Disabled = inputAgent.Disabled;
- agent.AllowRouting = inputAgent.AllowRouting;
+ agent.Type = inputAgent.Type;
agent.Profiles = inputAgent.Profiles;
agent.RoutingRules = inputAgent.RoutingRules;
agent.LlmConfig = inputAgent.LlmConfig;
@@ -336,9 +336,9 @@ namespace BotSharp.Core.Repository
query = query.Where(x => x.Disabled == filter.Disabled);
}
- if (filter.AllowRouting.HasValue)
+ if (filter.Type != null)
{
- query = query.Where(x => x.AllowRouting == filter.AllowRouting);
+ query = query.Where(x => x.Type == filter.Type);
}
if (filter.IsPublic.HasValue)
@@ -346,22 +346,6 @@ namespace BotSharp.Core.Repository
query = query.Where(x => x.IsPublic == filter.IsPublic);
}
- if (filter.IsRouter.HasValue)
- {
- var route = _services.GetRequiredService();
- query = filter.IsRouter.Value ?
- query.Where(x => route.AgentIds.Contains(x.Id)) :
- query.Where(x => !route.AgentIds.Contains(x.Id));
- }
-
- if (filter.IsEvaluator.HasValue)
- {
- var evaluate = _services.GetRequiredService();
- query = filter.IsEvaluator.Value ?
- query.Where(x => x.Id == evaluate.AgentId) :
- query.Where(x => x.Id != evaluate.AgentId);
- }
-
if (filter.AgentIds != null)
{
query = query.Where(x => filter.AgentIds.Contains(x.Id));
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs
index d9e276e5..76122be6 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs
@@ -204,10 +204,10 @@ namespace BotSharp.Core.Repository
{
var records = new List();
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir);
+ var pager = filter?.Pager ?? new Pagination();
var totalDirs = Directory.GetDirectories(dir);
- var dirs = totalDirs.Skip(filter.Pager.Offset).Take(filter.Pager.Size).ToList();
- foreach (var d in dirs)
+ foreach (var d in totalDirs)
{
var path = Path.Combine(d, CONVERSATION_FILE);
if (!File.Exists(path)) continue;
@@ -217,20 +217,20 @@ namespace BotSharp.Core.Repository
if (record == null) continue;
var matched = true;
- if (filter.Id != null) matched = matched && record.Id == filter.Id;
- if (filter.AgentId != null) matched = matched && record.AgentId == filter.AgentId;
- if (filter.Status != null) matched = matched && record.Status == filter.Status;
- if (filter.Channel != null) matched = matched && record.Channel == filter.Channel;
- if (filter.UserId != null) matched = matched && record.UserId == filter.UserId;
+ if (filter?.Id != null) matched = matched && record.Id == filter.Id;
+ if (filter?.AgentId != null) matched = matched && record.AgentId == filter.AgentId;
+ if (filter?.Status != null) matched = matched && record.Status == filter.Status;
+ if (filter?.Channel != null) matched = matched && record.Channel == filter.Channel;
+ if (filter?.UserId != null) matched = matched && record.UserId == filter.UserId;
if (!matched) continue;
records.Add(record);
}
-
+
return new PagedItems
{
- Items = records.OrderByDescending(x => x.CreatedTime),
- Count = totalDirs.Count(),
+ Items = records.OrderByDescending(x => x.CreatedTime).Skip(pager.Offset).Take(pager.Size),
+ Count = records.Count(),
};
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs
new file mode 100644
index 00000000..d6fb3dcb
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs
@@ -0,0 +1,44 @@
+using BotSharp.Abstraction.Functions;
+using BotSharp.Abstraction.Repositories.Filters;
+using BotSharp.Abstraction.Routing.Models;
+using BotSharp.Abstraction.Routing;
+
+namespace BotSharp.Core.Routing.Functions;
+
+public class FallbackToRouterFn : IFunctionCallback
+{
+ public string Name => "fallback_to_router";
+ private readonly IServiceProvider _services;
+ public FallbackToRouterFn(IServiceProvider services)
+ {
+ _services = services;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(message.FunctionArgs);
+ var agentService = _services.GetRequiredService();
+ var agents = await agentService.GetAgents(new AgentFilter
+ {
+ AgentName = args.AgentName
+ });
+ var targetAgent = agents.Items.FirstOrDefault();
+ if (targetAgent == null)
+ {
+ message.Content = $"Can't find routing agent {args.AgentName}";
+ return false;
+ }
+
+ var routing = _services.GetRequiredService();
+ routing.Replace(targetAgent.Id);
+
+ var router = _services.GetRequiredService();
+ message.CurrentAgentId = targetAgent.Id;
+ var response = await router.InstructLoop(message);
+
+ message.Content = response.Content;
+ message.StopCompletion = true;
+
+ return true;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
index a197b9ba..26f14f45 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
@@ -91,7 +91,7 @@ public class RouteToAgentFn : IFunctionCallback
var args = JsonSerializer.Deserialize(message.FunctionArgs);
var routing = _services.GetRequiredService();
- var routingRules = routing.GetRulesByName(args.AgentName);
+ var routingRules = routing.GetRulesByAgentName(args.AgentName);
if (routingRules == null || !routingRules.Any())
{
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
index 984df62c..0e1cce58 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
@@ -63,7 +63,6 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
var response = _dialogs.Last();
inst.Response = response.Content;
- inst.UnmatchedAgent = response.UnmatchedAgent;
return true;
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
index 47cfcc38..5b42f5d8 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
@@ -1,6 +1,8 @@
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing;
+using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Settings;
+using System.Diagnostics.Metrics;
namespace BotSharp.Core.Routing.Hooks;
@@ -17,26 +19,69 @@ public class RoutingAgentHook : AgentHookBase
public override bool OnInstructionLoaded(string template, Dictionary dict)
{
- if (!_routingSetting.AgentIds.Contains(_agent.Id))
+ if (_agent.Type != AgentType.Routing)
{
return base.OnInstructionLoaded(template, dict);
}
dict["router"] = _agent;
var routing = _services.GetRequiredService();
- dict["routing_agents"] = routing.GetRoutingItems();
- dict["routing_handlers"] = routing.GetHandlers();
+ var agents = routing.GetRoutableAgents(_agent.Profiles);
+ dict["routing_agents"] = agents;
+ dict["routing_handlers"] = routing.GetHandlers(_agent);
return base.OnInstructionLoaded(template, dict);
}
public override bool OnFunctionsLoaded(List functions)
{
- /*functions.Add(new FunctionDef
+ if (_agent.Type == AgentType.Task)
{
- Name = "fallback_to_router",
- Description = "If the user's request is beyond your capabilities, you can call this function for help."
- });*/
+ // check if enabled the routing rule
+ var routing = _services.GetRequiredService();
+ var rule = routing.GetRulesByAgentId(_agent.Id)
+ .FirstOrDefault(x => x.Type == RuleType.Fallback);
+ if (rule != null)
+ {
+ var agentService = _services.GetRequiredService();
+ var redirectAgent = agentService.GetAgent(rule.RedirectTo).Result;
+
+ var json = JsonSerializer.Serialize(new
+ {
+ user_goal_agent = new
+ {
+ type = "string",
+ description = $"{_agent.Name}"
+ },
+ next_action_agent = new
+ {
+ type = "string",
+ description = $"{redirectAgent.Name}"
+ },
+ reason = new
+ {
+ type = "string",
+ description = $"the reason why you need to fallback to [{redirectAgent.Name}] from [{_agent.Name}]"
+ },
+ });
+ functions.Add(new FunctionDef
+ {
+ Name = "fallback_to_router",
+ Description = $"If the user's request is beyond your capabilities, you can call this function to handle by other agent ({redirectAgent.Name}).",
+ Parameters =
+ {
+ Properties = JsonSerializer.Deserialize(json),
+ Required = new List
+ {
+ "user_goal_agent",
+ "next_action_agent",
+ "reason"
+ }
+ }
+ });
+ }
+ }
+
return base.OnFunctionsLoaded(functions);
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs
index 7b4dc318..946e6057 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs
@@ -37,14 +37,6 @@ public class RoutingPlugin : IBotSharpPlugin
services.AddScoped();
services.AddScoped();
- services.AddScoped(provider =>
- {
- var settingService = provider.GetRequiredService();
- var routingSettings = settingService.Bind("Router");
- if (routingSettings.Planner == nameof(HFPlanner))
- return provider.GetRequiredService();
- else
- return provider.GetRequiredService();
- });
+ services.AddScoped();
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs
new file mode 100644
index 00000000..01de9a29
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs
@@ -0,0 +1,21 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Planning;
+using BotSharp.Abstraction.Routing.Enums;
+using BotSharp.Core.Planning;
+
+namespace BotSharp.Core.Routing;
+
+public partial class RoutingService
+{
+ public IPlaner GetPlanner(Agent router)
+ {
+ var planner = router.RoutingRules.FirstOrDefault(x => x.Type == RuleType.Planner);
+
+ if (planner?.Field == nameof(HFPlanner))
+ return _services.GetRequiredService();
+ else if (planner?.Field == nameof(SequentialPlanner))
+ return _services.GetRequiredService();
+ else
+ return _services.GetRequiredService();
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
index 78b339fa..e144a688 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Agents.Models;
-using BotSharp.Abstraction.MLTasks.Settings;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Templating;
@@ -7,20 +6,19 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
- const int MAXIMUM_RECURSION_DEPTH = 3;
private int _currentRecursionDepth = 0;
public async Task InvokeAgent(string agentId, List dialogs)
{
- _currentRecursionDepth++;
- if (_currentRecursionDepth > MAXIMUM_RECURSION_DEPTH)
- {
- _logger.LogWarning($"Current recursive call depth greater than {MAXIMUM_RECURSION_DEPTH}, which will cause unexpected result.");
- return false;
- }
-
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(agentId);
+ _currentRecursionDepth++;
+ if (_currentRecursionDepth > agent.LlmConfig.MaxRecursionDepth)
+ {
+ _logger.LogWarning($"Current recursive call depth greater than {agent.LlmConfig.MaxRecursionDepth}, which will cause unexpected result.");
+ return false;
+ }
+
var chatCompletion = CompletionProvider.GetChatCompletion(_services,
agentConfig: agent.LlmConfig);
@@ -59,21 +57,11 @@ public partial class RoutingService
// Call functions
await conversationService.CallFunctions(message);
- // Router selected the wrong agent, handle this excluding the agent
- if (message.UnmatchedAgent)
- {
- // Save to memory dialogs
- var msg = RoleDialogModel.From(message,
- role: AgentRole.Function,
- content: message.Content);
- msg.UnmatchedAgent = true;
- dialogs.Add(msg);
- }
// Pass execution result to LLM to get response
- else if (!message.StopCompletion)
+ if (!message.StopCompletion)
{
var routing = _services.GetRequiredService();
-
+
// Find response template
var templateService = _services.GetRequiredService();
var responseTemplate = await templateService.RenderFunctionResponse(message.CurrentAgentId, message);
@@ -86,8 +74,8 @@ public partial class RoutingService
else
{
// Save to memory dialogs
- dialogs.Add(RoleDialogModel.From(message,
- role: AgentRole.Function,
+ dialogs.Add(RoleDialogModel.From(message,
+ role: AgentRole.Function,
content: message.Content));
// Send to Next LLM
@@ -97,8 +85,8 @@ public partial class RoutingService
}
else
{
- dialogs.Add(RoleDialogModel.From(message,
- role: AgentRole.Assistant,
+ dialogs.Add(RoleDialogModel.From(message,
+ role: AgentRole.Assistant,
content: message.Content));
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
index d70cc15f..b94903af 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
@@ -32,7 +32,7 @@ public partial class RoutingService : IRoutingService
_logger = logger;
}
- public async Task ExecuteDirectly(Agent agent, RoleDialogModel message)
+ public async Task InstructDirect(Agent agent, RoleDialogModel message)
{
var handlers = _services.GetServices();
@@ -73,9 +73,10 @@ public partial class RoutingService : IRoutingService
var dialogs = conv.GetDialogHistory();
var context = _services.GetRequiredService();
- var planner = _services.GetRequiredService();
var executor = _services.GetRequiredService();
+ var planner = GetPlanner(_router);
+
context.Push(_router.Id);
int loopCount = 0;
@@ -85,7 +86,6 @@ public partial class RoutingService : IRoutingService
var conversation = await GetConversationContent(dialogs);
_router.TemplateDict["conversation"] = conversation;
- _router.TemplateDict["planner"] = _settings.Planner;
// Get instruction from Planner
var inst = await planner.GetNextInstruction(_router, message.MessageId);
@@ -109,9 +109,9 @@ public partial class RoutingService : IRoutingService
return response;
}
- public List GetHandlers()
+ public List GetHandlers(Agent router)
{
- var planer = _services.GetRequiredService();
+ var planer = GetPlanner(router);
return _services.GetServices()
.Where(x => x.Planers == null || x.Planers.Contains(planer.GetType().Name))
@@ -134,7 +134,7 @@ public partial class RoutingService : IRoutingService
var filter = new AgentFilter
{
Disabled = false,
- AllowRouting = true
+ Type = AgentType.Task
};
var agents = db.GetAgents(filter);
var records = agents.SelectMany(x =>
@@ -147,52 +147,62 @@ public partial class RoutingService : IRoutingService
return x.RoutingRules;
}).ToArray();
- // Filter agents by profile
- var state = _services.GetRequiredService();
- var channel = state.GetState("channel");
- var specifiedProfile = agents.FirstOrDefault(x => x.Profiles.Contains(channel));
- if (specifiedProfile != null)
- {
- records = records.Where(x => specifiedProfile.Profiles.Contains(channel)).ToArray();
- }
-
return records;
}
#if !DEBUG
[MemoryCache(10 * 60)]
#endif
- public RoutingItem[] GetRoutingItems()
+ public RoutableAgent[] GetRoutableAgents(List profiles)
{
var db = _services.GetRequiredService();
var filter = new AgentFilter
{
Disabled = false,
- AllowRouting = true
+ Type = AgentType.Task
};
+
var agents = db.GetAgents(filter);
- return agents.Select(x => new RoutingItem
+ var routableAgents = agents.Select(x => new RoutableAgent
{
AgentId = x.Id,
Description = x.Description,
Name = x.Name,
+ Profiles = x.Profiles,
RequiredFields = x.RoutingRules
.Where(p => p.Required)
- .Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
+ .Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.FieldType)
{
Required = p.Required
}).ToList(),
OptionalFields = x.RoutingRules
.Where(p => !p.Required)
- .Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
+ .Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.FieldType)
{
Required = p.Required
}).ToList()
}).ToArray();
+
+ // Handle profile.
+ // Router profile must match the agent profile
+ if (routableAgents.Length > 0 && profiles.Count > 0)
+ {
+ routableAgents = routableAgents.Where(x => x.Profiles != null &&
+ x.Profiles.Exists(x1 => profiles.Exists(y => x1 == y)))
+ .ToArray();
+ }
+ else if (profiles == null || profiles.Count == 0)
+ {
+ routableAgents = routableAgents.Where(x => x.Profiles == null ||
+ x.Profiles.Count == 0)
+ .ToArray();
+ }
+
+ return routableAgents;
}
- public RoutingRule[] GetRulesByName(string name)
+ public RoutingRule[] GetRulesByAgentName(string name)
{
return GetRoutingRecords()
.Where(x => x.AgentName.ToLower() == name.ToLower())
diff --git a/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs b/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs
index 3aba223f..62d5c3e0 100644
--- a/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs
+++ b/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs
@@ -25,7 +25,7 @@ public class TemplateRender : ITemplateRender
_options.MemberAccessStrategy.Register();
_options.MemberAccessStrategy.Register();
_options.MemberAccessStrategy.Register();
- _options.MemberAccessStrategy.Register();
+ _options.MemberAccessStrategy.Register();
_options.MemberAccessStrategy.Register();
}
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json
index b701d67b..b17531f4 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json
@@ -1,10 +1,12 @@
{
+ "id": "01e2fc5c-2c89-4ec7-8470-7688608b496c",
"name": "Chatbot",
"description": "AI chatbot that can do variaty of tasks",
+ "type": "task",
"createdDateTime": "2024-01-15T10:39:32Z",
"updatedDateTime": "2024-01-15T14:39:32Z",
- "id": "01e2fc5c-2c89-4ec7-8470-7688608b496c",
"iconUrl": "/images/users/bot.png",
"disabled": false,
- "isPublic": true
+ "isPublic": true,
+ "profiles": [ "standalone" ]
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json
index a92a4614..18e856b7 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json
@@ -1,10 +1,18 @@
{
+ "id": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
"name": "AI Assistant",
"description": "AI assistant that can complete many different tasks",
+ "type": "routing",
"createdDateTime": "2023-08-18T10:39:32.2349685Z",
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
- "id": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
"iconUrl": "https://cdn.iconscout.com/icon/premium/png-256-thumb/route-1613278-1368497.png",
"disabled": false,
- "isPublic": true
+ "isPublic": true,
+ "profiles": [ "default" ],
+ "routingRules": [
+ {
+ "type": "planner",
+ "field": "HFPlanner"
+ }
+ ]
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid
index eca5ac78..9147979f 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid
@@ -4,6 +4,7 @@ You're {{router.name}} ({{router.description}}). Follow these steps to handle us
3. Determine which agent is suitable to handle this conversation.
4. Re-think on whether the function you chose matches the reason.
5. For agent required arguments, leave it as blank object if user doesn't provide it.
+6. Response must be in JSON format.
[FUNCTIONS]
{% for handler in routing_handlers %}
@@ -36,4 +37,4 @@ Optional args:
{% endfor %}
[CONVERSATION]
-{{ conversation }}
\ No newline at end of file
+{{ conversation }}
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.hf_planner.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid
similarity index 54%
rename from src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.hf_planner.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid
index 158bf965..20874a60 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.hf_planner.liquid
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid
@@ -1 +1 @@
-Break down the user’s most recent needs and figure out the next steps. Response must be in appropriate JSON format.
\ No newline at end of file
+Break down the user’s most recent needs and figure out the next steps.
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid
similarity index 74%
rename from src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid
index 2f74b54b..449bd4d7 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid
@@ -1,4 +1,3 @@
What is the next step based on the CONVERSATION?
-Response must be in required JSON format without any other contents.
Route to the Agent that last handled the conversation if necessary.
If user wants to speak to customer service, use function human_intervention_needed.
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid
new file mode 100644
index 00000000..a1025e50
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid
@@ -0,0 +1,2 @@
+In order to execute the instructions listed by the user in the order specified by the user.
+What is the next step based on the CONVERSATION?
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
index 9259cb54..9183be01 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
@@ -1,3 +1,5 @@
+using BotSharp.Abstraction.Agents.Models;
+
namespace BotSharp.OpenAPI.Controllers;
[Authorize]
@@ -28,10 +30,20 @@ public class AgentController : ControllerBase
}
[HttpGet("/agents")]
- public async Task> GetAgents([FromQuery] AgentFilter filter)
+ public async Task> GetAgents([FromQuery] AgentFilter filter)
{
- var agents = await _agentService.GetAgents(filter);
- return agents.Select(x => AgentViewModel.FromAgent(x)).ToList();
+ var pagedAgents = await _agentService.GetAgents(filter);
+ var items = new List();
+ foreach (var agent in pagedAgents.Items)
+ {
+ var renderedAgent = await _agentService.LoadAgent(agent.Id);
+ items.Add(renderedAgent);
+ }
+ return new PagedItems
+ {
+ Items = items.Select(x => AgentViewModel.FromAgent(x)).ToList(),
+ Count = pagedAgents.Count
+ };
}
[HttpPost("/agent")]
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
index 46a1b721..58378ba5 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
@@ -30,8 +30,8 @@ public class ConversationController : ControllerBase
return ConversationViewModel.FromSession(conv);
}
- [HttpPost("/conversations")]
- public async Task> GetConversations([FromBody] ConversationFilter filter)
+ [HttpGet("/conversations")]
+ public async Task> GetConversations([FromQuery] ConversationFilter filter)
{
var service = _services.GetRequiredService();
var conversations = await service.GetConversations(filter);
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs
index 36612852..54cdae14 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs
@@ -16,8 +16,8 @@ public class PluginController : ControllerBase
_settings = settings;
}
- [HttpPost("/plugins")]
- public PagedItems GetPlugins([FromBody] PluginFilter filter)
+ [HttpGet("/plugins")]
+ public PagedItems GetPlugins([FromQuery] PluginFilter filter)
{
var loader = _services.GetRequiredService();
return loader.GetPagedPlugins(_services, filter);
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
index fe6ce7e2..b5f8ea82 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
@@ -8,6 +8,7 @@ public class AgentCreationModel
{
public string Name { get; set; }
public string Description { get; set; }
+ public string Type { get; set; } = AgentType.Task;
///
/// LLM default system instructions
@@ -57,7 +58,7 @@ public class AgentCreationModel
Responses = Responses,
Samples = Samples,
IsPublic = IsPublic,
- AllowRouting = AllowRouting,
+ Type = Type,
Disabled = Disabled,
Profiles = Profiles,
RoutingRules = RoutingRules?
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
index 56b6d968..0a461ea6 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
@@ -9,7 +9,7 @@ public class AgentUpdateModel
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
-
+ public string Type { get; set; } = AgentType.Task;
///
/// Instruction
///
@@ -62,7 +62,7 @@ public class AgentUpdateModel
Description = Description ?? string.Empty,
IsPublic = IsPublic,
Disabled = Disabled,
- AllowRouting = AllowRouting,
+ Type = Type,
Profiles = Profiles ?? new List(),
RoutingRules = RoutingRules?
.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
index 663dfd4a..3c35b3af 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
@@ -11,23 +11,26 @@ public class AgentViewModel
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
+ public string Type { get; set; } = AgentType.Task;
public string Instruction { get; set; }
public List Templates { get; set; }
public List Functions { get; set; }
public List Responses { get; set; }
public List Samples { get; set; }
+
[JsonPropertyName("is_public")]
public bool IsPublic { get; set; }
- [JsonPropertyName("is_router")]
- public bool IsRouter { get; set; }
+ [JsonPropertyName("is_host")]
+ public bool IsHost { get; set; }
- [JsonPropertyName("allow_routing")]
- public bool AllowRouting { get; set; }
public bool Disabled { get; set; }
+
[JsonPropertyName("icon_url")]
public string IconUrl { get; set; }
+
public List Profiles { get; set; }
+ = new List();
[JsonPropertyName("routing_rules")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
@@ -52,17 +55,17 @@ public class AgentViewModel
Id = agent.Id,
Name = agent.Name,
Description = agent.Description,
+ Type = agent.Type,
Instruction = agent.Instruction,
Templates = agent.Templates,
Functions = agent.Functions,
Responses = agent.Responses,
Samples = agent.Samples,
IsPublic= agent.IsPublic,
- IsRouter = agent.IsRouter,
+ IsHost = agent.IsHost,
Disabled = agent.Disabled,
IconUrl = agent.IconUrl,
- AllowRouting = agent.AllowRouting,
- Profiles = agent.Profiles,
+ Profiles = agent.Profiles ?? new List(),
RoutingRules = agent.RoutingRules,
LlmConfig = agent.LlmConfig,
Plugin = agent.Plugin,
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs
index f3083abd..1a4706a3 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs
@@ -16,6 +16,12 @@ public class UserViewModel
public string Role { get; set; } = UserRole.Client;
[JsonPropertyName("full_name")]
public string FullName => $"{FirstName} {LastName}";
+ [JsonPropertyName("external_id")]
+ public string? ExternalId { get; set; }
+ [JsonPropertyName("create_date")]
+ public DateTime CreateDate { get; set; }
+ [JsonPropertyName("update_date")]
+ public DateTime UpdateDate { get; set; }
public static UserViewModel FromUser(User user)
{
@@ -36,7 +42,10 @@ public class UserViewModel
FirstName = user.FirstName,
LastName = user.LastName,
Email = user.Email,
- Role = user.Role
+ Role = user.Role,
+ ExternalId = user.ExternalId,
+ CreateDate = user.CreatedTime,
+ UpdateDate = user.UpdatedTime
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
index 34cfe762..bf563670 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
@@ -235,7 +235,11 @@ public class ChatCompletionProvider : IChatCompletion
}
else if (message.Role == ChatRole.User)
{
- chatCompletionsOptions.Messages.Add(new ChatRequestUserMessage(message.Content));
+ chatCompletionsOptions.Messages.Add(new ChatRequestUserMessage(message.Content)
+ {
+ // To display Planner name in log
+ Name = message.FunctionName
+ });
}
else if (message.Role == ChatRole.Assistant)
{
@@ -268,6 +272,11 @@ public class ChatCompletionProvider : IChatCompletion
.Where(x => x.Role == AgentRole.System)
.Select(x => x as ChatRequestSystemMessage).Select(x =>
{
+ if (!string.IsNullOrEmpty(x.Name))
+ {
+ // To display Agent name in log
+ return $"[{x.Name}]: {x.Content}";
+ }
return $"{x.Role}: {x.Content}";
}));
prompt += $"{verbose}\r\n";
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs
index 710d1a41..bec0a01a 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs
@@ -19,5 +19,6 @@ public class ChatHubPlugin : IBotSharpPlugin
// Register hooks
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
}
}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs
index 1b9a0089..bad8cf2b 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs
@@ -100,6 +100,7 @@ public class ChatHubConversationHook : ConversationHookBase
public override async Task OnResponseGenerated(RoleDialogModel message)
{
var conv = _services.GetRequiredService();
+ var state = _services.GetRequiredService();
var json = JsonSerializer.Serialize(new ChatResponseModel()
{
@@ -115,7 +116,20 @@ public class ChatHubConversationHook : ConversationHookBase
}
}, _serializerOptions);
await _chatHub.Clients.User(_user.Id).SendAsync("OnMessageReceivedFromAssistant", json);
+ await _chatHub.Clients.User(_user.Id).SendAsync("OnConversateStatesGenerated", BuildConversationStates(conv.ConversationId, state.GetStates()));
await base.OnResponseGenerated(message);
}
+
+ private string BuildConversationStates(string conversationId, Dictionary states)
+ {
+ var model = new ConversationStateLogModel
+ {
+ ConvsersationId = conversationId,
+ States = JsonSerializer.Serialize(states, _serializerOptions),
+ CreateTime = DateTime.UtcNow
+ };
+
+ return JsonSerializer.Serialize(model, _serializerOptions);
+ }
}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
index b6a91787..8b0aa2cd 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
@@ -5,21 +5,27 @@ using Microsoft.AspNetCore.SignalR;
namespace BotSharp.Plugin.ChatHub.Hooks;
-public class StreamingLogHook : IContentGeneratingHook
+public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook
{
private readonly ConversationSetting _convSettings;
+ private readonly JsonSerializerOptions _serializerOptions;
private readonly IServiceProvider _services;
private readonly IHubContext _chatHub;
- private readonly JsonSerializerOptions _serializerOptions;
+ private readonly IConversationStateService _state;
+ private readonly IUserIdentity _user;
public StreamingLogHook(
ConversationSetting convSettings,
IServiceProvider serivces,
- IHubContext chatHub)
+ IHubContext chatHub,
+ IConversationStateService state,
+ IUserIdentity user)
{
_convSettings = convSettings;
_services = serivces;
_chatHub = chatHub;
+ _state = state;
+ _user = user;
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
@@ -27,17 +33,27 @@ public class StreamingLogHook : IContentGeneratingHook
AllowTrailingCommas = true
};
}
+ public override async Task OnMessageReceived(RoleDialogModel message)
+ {
+ var conversationId = _state.GetConversationId();
+ var log = $"MessageId: {message.MessageId} ==>\r\n{message.Role}: {message.Content}";
+ await _chatHub.Clients.User(_user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, _user.UserName, log));
+ }
public async Task BeforeGenerating(Agent agent, List conversations)
{
if (!_convSettings.ShowVerboseLog) return;
- var user = _services.GetRequiredService();
- var states = _services.GetRequiredService();
- var conversationId = states.GetConversationId();
+ /*var _state = _services.GetRequiredService();
+ var conversationId = _state.GetConversationId();
var dialog = conversations.Last();
var log = $"{dialog.Role}: {dialog.Content} [msg_id: {dialog.MessageId}] ==>";
- await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, log));
+ await _chatHub.Clients.User(_user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, log));*/
+ }
+
+ public override async Task OnFunctionExecuted(RoleDialogModel message)
+ {
+
}
public async Task AfterGenerated(RoleDialogModel message, TokenStatsModel tokenStats)
@@ -45,24 +61,24 @@ public class StreamingLogHook : IContentGeneratingHook
if (!_convSettings.ShowVerboseLog) return;
var agentService = _services.GetRequiredService();
- var states = _services.GetRequiredService();
- var conversationId = states.GetConversationId();
+ var conversationId = _state.GetConversationId();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _chatHub.Clients.User(_user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, agent?.Name, tokenStats.Prompt));
+
var log = message.Role == AgentRole.Function ?
$"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs})" :
- $"[{agent?.Name}]: {message.Content}" + $" <== [msg_id: {message.MessageId}]";
-
- var user = _services.GetRequiredService();
- await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, tokenStats.Prompt));
- await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, log));
+ $"[{agent?.Name}]: {message.Content}";
+ log += $"\r\n<== MessageId: {message.MessageId}";
+ await _chatHub.Clients.User(_user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, agent?.Name, log));
}
- private string BuildLog(string conversationId, string content)
+ private string BuildLog(string conversationId, string? name, string content)
{
var log = new StreamingLogModel
{
ConversationId = conversationId,
+ Name = name,
Content = content,
CreateTime = DateTime.UtcNow
};
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs
index f2bad9bf..68d5bd25 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs
@@ -27,7 +27,6 @@ public class SearchKnowledgesFn : IFunctionCallback
if (string.IsNullOrEmpty(knowledge))
{
message.Content = "Can't find any relevant data in local knowledge base.";
- message.UnmatchedAgent = true;
}
return true;
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
index b0f1d6e1..603f312e 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
@@ -6,6 +6,7 @@ public class AgentDocument : MongoBase
{
public string Name { get; set; }
public string Description { get; set; }
+ public string Type { get; set; }
public string? IconUrl { get; set; }
public string Instruction { get; set; }
public List Templates { get; set; }
@@ -13,7 +14,6 @@ public class AgentDocument : MongoBase
public List Responses { get; set; }
public List Samples { get; set; }
public bool IsPublic { get; set; }
- public bool AllowRouting { get; set; }
public bool Disabled { get; set; }
public List Profiles { get; set; }
public List RoutingRules { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
index 36fc9ff9..9a0f0cee 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
@@ -29,8 +29,8 @@ public partial class MongoRepository
case AgentField.Disabled:
UpdateAgentDisabled(agent.Id, agent.Disabled);
break;
- case AgentField.AllowRouting:
- UpdateAgentAllowRouting(agent.Id, agent.AllowRouting);
+ case AgentField.Type:
+ UpdateAgentType(agent.Id, agent.Type);
break;
case AgentField.Profiles:
UpdateAgentProfiles(agent.Id, agent.Profiles);
@@ -109,11 +109,11 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update);
}
- private void UpdateAgentAllowRouting(string agentId, bool allowRouting)
+ private void UpdateAgentType(string agentId, string type)
{
var filter = Builders.Filter.Eq(x => x.Id, agentId);
var update = Builders.Update
- .Set(x => x.AllowRouting, allowRouting)
+ .Set(x => x.Type, type)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Agents.UpdateOne(filter, update);
@@ -225,7 +225,7 @@ public partial class MongoRepository
.Set(x => x.Name, agent.Name)
.Set(x => x.Description, agent.Description)
.Set(x => x.Disabled, agent.Disabled)
- .Set(x => x.AllowRouting, agent.AllowRouting)
+ .Set(x => x.Type, agent.Type)
.Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList())
.Set(x => x.Instruction, agent.Instruction)
@@ -267,7 +267,7 @@ public partial class MongoRepository
Samples = agent.Samples ?? new List(),
IsPublic = agent.IsPublic,
Disabled = agent.Disabled,
- AllowRouting = agent.AllowRouting,
+ Type = agent.Type,
Profiles = agent.Profiles,
RoutingRules = !agent.RoutingRules.IsNullOrEmpty() ? agent.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(agent.Id, agent.Name, r))
@@ -292,9 +292,9 @@ public partial class MongoRepository
filters.Add(builder.Eq(x => x.Disabled, filter.Disabled.Value));
}
- if (filter.AllowRouting.HasValue)
+ if (filter.Type != null)
{
- filters.Add(builder.Eq(x => x.AllowRouting, filter.AllowRouting.Value));
+ filters.Add(builder.Eq(x => x.Type, filter.Type));
}
if (filter.IsPublic.HasValue)
@@ -302,32 +302,6 @@ public partial class MongoRepository
filters.Add(builder.Eq(x => x.IsPublic, filter.IsPublic.Value));
}
- if (filter.IsRouter.HasValue)
- {
- var route = _services.GetRequiredService();
- if (filter.IsRouter.Value)
- {
- filters.Add(builder.In(x => x.Id, route.AgentIds));
- }
- else
- {
- filters.Add(builder.Nin(x => x.Id, route.AgentIds));
- }
- }
-
- if (filter.IsEvaluator.HasValue)
- {
- var evaluate = _services.GetRequiredService();
- if (filter.IsEvaluator.Value)
- {
- filters.Add(builder.Eq(x => x.Id, evaluate.AgentId));
- }
- else
- {
- filters.Add(builder.Ne(x => x.Id, evaluate.AgentId));
- }
- }
-
if (filter.AgentIds != null)
{
filters.Add(builder.In(x => x.Id, filter.AgentIds));
@@ -354,7 +328,7 @@ public partial class MongoRepository
Samples = x.Samples ?? new List(),
IsPublic = x.IsPublic,
Disabled = x.Disabled,
- AllowRouting = x.AllowRouting,
+ Type = x.Type,
Profiles = x.Profiles,
RoutingRules = !x.RoutingRules.IsNullOrEmpty() ? x.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(x.Id, x.Name, r))
@@ -418,7 +392,7 @@ public partial class MongoRepository
.ToList() ?? new List(),
Samples = x.Samples ?? new List(),
IsPublic = x.IsPublic,
- AllowRouting = x.AllowRouting,
+ Type = x.Type,
Disabled = x.Disabled,
Profiles = x.Profiles,
RoutingRules = x.RoutingRules?
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
index 84ccce6d..15a2406b 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
@@ -210,6 +210,7 @@ public partial class MongoRepository
var builder = Builders.Filter;
var filters = new List>() { builder.Empty };
+ if (!string.IsNullOrEmpty(filter.Id)) filters.Add(builder.Eq(x => x.Id, filter.Id));
if (!string.IsNullOrEmpty(filter.AgentId)) filters.Add(builder.Eq(x => x.AgentId, filter.AgentId));
if (!string.IsNullOrEmpty(filter.Status)) filters.Add(builder.Eq(x => x.Status, filter.Status));
if (!string.IsNullOrEmpty(filter.Channel)) filters.Add(builder.Eq(x => x.Channel, filter.Channel));
@@ -217,7 +218,8 @@ public partial class MongoRepository
var filterDef = builder.And(filters);
var sortDefinition = Builders.Sort.Descending(x => x.CreatedTime);
- var conversationDocs = _dc.Conversations.Find(filterDef).Sort(sortDefinition).Skip(filter.Pager.Offset).Limit(filter.Pager.Size).ToList();
+ var pager = filter?.Pager ?? new Pagination();
+ var conversationDocs = _dc.Conversations.Find(filterDef).Sort(sortDefinition).Skip(pager.Offset).Limit(pager.Size).ToList();
var count = _dc.Conversations.CountDocuments(filterDef);
foreach (var conv in conversationDocs)
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs
index 16b8080c..17e59c2e 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs
@@ -54,7 +54,7 @@ public partial class MongoRepository
.ToList() ?? new List(),
Samples = x.Samples ?? new List(),
IsPublic = x.IsPublic,
- AllowRouting = x.AllowRouting,
+ Type = x.Type,
Disabled = x.Disabled,
Profiles = x.Profiles,
RoutingRules = x.RoutingRules?
@@ -77,7 +77,7 @@ public partial class MongoRepository
.Set(x => x.Responses, agent.Responses)
.Set(x => x.Samples, agent.Samples)
.Set(x => x.IsPublic, agent.IsPublic)
- .Set(x => x.AllowRouting, agent.AllowRouting)
+ .Set(x => x.Type, agent.Type)
.Set(x => x.Disabled, agent.Disabled)
.Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules)
diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs
index d3ed4bdf..8c6d826e 100644
--- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs
+++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs
@@ -53,7 +53,7 @@ public class RoutingConversationHook: ConversationHookBase
public override async Task OnResponseGenerated(RoleDialogModel message)
{
var routerSettings = _services.GetRequiredService();
- bool saveFlag = !routerSettings.AgentIds.Contains(message.CurrentAgentId);
+ bool saveFlag = _agent.Type != AgentType.Routing;
if (saveFlag)
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.Selenium.csproj b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.Selenium.csproj
deleted file mode 100644
index 20ca5175..00000000
--- a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.Selenium.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- netstandard2.1
- enable
- $(MSBuildProjectName.Replace(" ", "_"))s
-
-
-
-
-
-
-
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs
index 2c08a0ad..d3cb5c7d 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs
@@ -1,4 +1,5 @@
using BotSharp.Plugin.WebDriver.Services;
+using System.Threading;
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
@@ -10,22 +11,49 @@ public partial class PlaywrightWebDriver
var body = await _instance.Page.QuerySelectorAsync("body");
var str = new List();
- var inputs = await body.QuerySelectorAllAsync("input");
+ var inputs = await body.QuerySelectorAllAsync("select");
foreach (var input in inputs)
{
- var text = await input.TextContentAsync();
+ var html = "";
+ str.Add(html);
}
var driverService = _services.GetRequiredService();
@@ -36,10 +64,52 @@ public partial class PlaywrightWebDriver
throw new Exception($"Can't locate the web element {context.ElementName}.");
}
- var element = _instance.Page.Locator(htmlElementContextOut.TagName).Nth(htmlElementContextOut.Index);
+ ILocator element = default;
+ if (!string.IsNullOrEmpty(htmlElementContextOut.ElementId))
+ {
+ // await _instance.Page.WaitForSelectorAsync($"#{htmlElementContextOut.ElementId}", new PageWaitForSelectorOptions { Timeout = 3 });
+ element = _instance.Page.Locator($"#{htmlElementContextOut.ElementId}");
+ }
+ else
+ {
+ element = _instance.Page.Locator(htmlElementContextOut.TagName).Nth(htmlElementContextOut.Index);
+ }
+
try
{
- await element.FillAsync(context.InputText);
+ var isVisible = await element.IsVisibleAsync();
+
+ if (!isVisible)
+ {
+ // Select the element you want to make visible (replace with your own selector)
+ var control = await _instance.Page.QuerySelectorAsync($"#{htmlElementContextOut.ElementId}");
+
+ // Show the element by modifying its CSS styles
+ await _instance.Page.EvaluateAsync(@"(element) => {
+ element.style.display = 'block';
+ element.style.visibility = 'visible';
+ }", control);
+ }
+
+ await element.FocusAsync();
+ await element.SelectOptionAsync(new SelectOptionValue
+ {
+ Label = context.UpdateValue
+ });
+
+ // Click on the blank area to activate posting
+ // await body.ClickAsync();
+ if (!isVisible)
+ {
+ // Select the element you want to make visible (replace with your own selector)
+ var control = await _instance.Page.QuerySelectorAsync($"#{htmlElementContextOut.ElementId}");
+
+ // Show the element by modifying its CSS styles
+ await _instance.Page.EvaluateAsync(@"(element) => {
+ element.style.display = 'none';
+ element.style.visibility = 'hidden';
+ }", control);
+ }
}
catch (Exception ex)
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs
index a325a076..abfc300f 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs
@@ -4,6 +4,7 @@ public partial class PlaywrightWebDriver
{
private readonly IServiceProvider _services;
private readonly PlaywrightInstance _instance;
+ public PlaywrightInstance Instance => _instance;
public PlaywrightWebDriver(IServiceProvider services, PlaywrightInstance instance)
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs
index 4431e1e3..1002351b 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs
@@ -23,9 +23,10 @@ public class ChangeListValueFn : IFunctionCallback
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _driver.Instance.Page.WaitForLoadStateAsync(LoadState.Load);
await _driver.ChangeListValue(agent, args, message.MessageId);
- message.Content = "Update successfully.";
+ message.Content = $"Updat the value of \"${args.ElementName}\" to \"{args.UpdateValue}\" successfully.";
return true;
}
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ClickButtonFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ClickButtonFn.cs
index bb4b81f9..afa8da5d 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ClickButtonFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ClickButtonFn.cs
@@ -23,9 +23,10 @@ public class ClickButtonFn : IFunctionCallback
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _driver.Instance.Page.WaitForLoadStateAsync(LoadState.Load);
await _driver.ClickElement(agent, args, message.MessageId);
- message.Content = "Executed successfully.";
+ message.Content = $"Click button {args.ElementName} successfully.";
return true;
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ExtractDataFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ExtractDataFn.cs
index 82692bfb..71c3fa39 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ExtractDataFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ExtractDataFn.cs
@@ -23,6 +23,7 @@ public class ExtractDataFn : IFunctionCallback
var args = JsonSerializer.Deserialize(message.FunctionArgs);
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _driver.Instance.Page.WaitForLoadStateAsync(LoadState.Load);
message.Content = await _driver.ExtractData(agent, args, message.MessageId);
return true;
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserPasswordFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserPasswordFn.cs
index 30aae332..ccafd721 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserPasswordFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserPasswordFn.cs
@@ -23,6 +23,7 @@ public class InputUserPasswordFn : IFunctionCallback
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _driver.Instance.Page.WaitForLoadStateAsync(LoadState.Load);
await _driver.InputUserPassword(agent, args, message.MessageId);
message.Content = "Input password successfully";
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserTextFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserTextFn.cs
index 246c6011..856203ed 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserTextFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/InputUserTextFn.cs
@@ -23,9 +23,11 @@ public class InputUserTextFn : IFunctionCallback
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _driver.Instance.Page.WaitForLoadStateAsync(LoadState.Load);
await _driver.InputUserText(agent, args, message.MessageId);
- message.Content = "Input text successfully.";
+ message.Content = $"Input text \"{args.InputText}\" successfully.";
+
return true;
}
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs
index 94e18cae..8a7323da 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs
@@ -20,9 +20,7 @@ public class OpenBrowserFn : IFunctionCallback
{
var args = JsonSerializer.Deserialize(message.FunctionArgs);
var browser = await _driver.LaunchBrowser(args.Url);
- message.Content = string.IsNullOrEmpty(args.Url) ? "Launch browser successfully." : $"Open website successfully.";
- message.Content += "\r\nWhat would you like to do next?";
- message.StopCompletion = true;
+ message.Content = string.IsNullOrEmpty(args.Url) ? $"Launch browser with blank page successfully." : $"Open website {args.Url} successfully.";
return true;
}
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/HtmlElementContextOut.cs b/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/HtmlElementContextOut.cs
index a325a4f6..a0fbfaf6 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/HtmlElementContextOut.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/HtmlElementContextOut.cs
@@ -4,6 +4,9 @@ namespace BotSharp.Plugin.WebDriver.LlmContexts;
public class HtmlElementContextOut
{
+ [JsonPropertyName("element_id")]
+ public string ElementId { get; set; }
+
[JsonPropertyName("tag_name")]
public string TagName { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json
index d2250da1..e06597f9 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json
@@ -1,9 +1,12 @@
{
- "name": "Web Driver",
- "description": "Perform a specific action on a web browser",
- "createdDateTime": "2024-01-02T00:00:00Z",
- "updatedDateTime": "2024-01-02T00:00:00Z",
- "id": "f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b",
- "allowRouting": true,
- "isPublic": true
- }
\ No newline at end of file
+ "id": "f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b",
+ "name": "Web Driver",
+ "description": "Perform a specific action on a web browser",
+ "type": "task",
+ "createdDateTime": "2024-01-02T00:00:00Z",
+ "updatedDateTime": "2024-01-02T00:00:00Z",
+ "isPublic": true,
+ "llmConfig": {
+ "max_recursion_depth": 10
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json
index 78128f01..49e4770b 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json
@@ -7,7 +7,7 @@
"properties": {
"url": {
"type": "string",
- "description": "website url."
+ "description": "website url starts with https://"
}
},
"required": ["url"]
@@ -67,7 +67,7 @@
"properties": {
"element_name": {
"type": "string",
- "description": "the html input box element name."
+ "description": "the html selection element name."
},
"update_value": {
"type": "string",
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instruction.liquid b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instruction.liquid
index 4f6d65dd..c41ef235 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instruction.liquid
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instruction.liquid
@@ -3,6 +3,8 @@ You are a Web Driver that can manipulate web elements through automation tools.
Follow below steps to response:
1. Analyze user's latest request in the conversation.
2. Call appropriate function to execute the instruction.
+3. If user requests execute multiple steps, execute them sequentially.
Additional response requirements:
-* Call function input_user_password if user wants to input password.
\ No newline at end of file
+* Call function input_user_password if user wants to input password.
+* Don't do extra steps if user didn't ask.
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/templates/html_parser.liquid b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/templates/html_parser.liquid
index 2e9c8bf5..c1991861 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/templates/html_parser.liquid
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/templates/html_parser.liquid
@@ -1,5 +1,6 @@
{{ html_content }}
=== According to above HTML ===
-Find the html element tag name of "{{ element_name }}".
-Output in JSON format {"tag_name": "", "index": -1} with appropriate values, the "index" starts with 0.
\ No newline at end of file
+Find the html element in the similar meaning of "{{ element_name }}".
+Output in JSON format {"tag_name": "", "element_id": "populated if element has id", "index": -1} with appropriate values.
+The index is the position of the element which starts with 0.
\ No newline at end of file
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 2f240b10..244824c6 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -60,10 +60,6 @@
],
"Router": {
- "AgentIds": [
- "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
- ],
- "Planner": "NaivePlanner"
},
"Evaluator": {
diff --git a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj
index 041ba8e5..77ba7e96 100644
--- a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj
+++ b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.1
@@ -35,13 +35,9 @@
-
-
-
-
@@ -91,27 +87,15 @@
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
index 6b2a2771..09c08cb6 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
@@ -6,6 +6,7 @@
"id": "b284db86-e9c2-4c25-a59e-4649797dd130",
"allowRouting": true,
"isPublic": true,
+ "profiles": [ "pizza" ],
"routingRules": [
{
"field": "order_number",
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
index bed04b3f..23323f63 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
@@ -5,5 +5,6 @@
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
"id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd",
"allowRouting": true,
- "isPublic": true
+ "isPublic": true,
+ "profiles": [ "pizza" ]
}
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/agents.json b/tests/BotSharp.Plugin.PizzaBot/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/agents.json
deleted file mode 100644
index 32960f8c..00000000
--- a/tests/BotSharp.Plugin.PizzaBot/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/agents.json
+++ /dev/null
@@ -1,2 +0,0 @@
-[
-]
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/users/456e35c5-caf0-4d45-9084-b44a8ca717e4/agents.json b/tests/BotSharp.Plugin.PizzaBot/data/users/456e35c5-caf0-4d45-9084-b44a8ca717e4/agents.json
deleted file mode 100644
index 9ed093a2..00000000
--- a/tests/BotSharp.Plugin.PizzaBot/data/users/456e35c5-caf0-4d45-9084-b44a8ca717e4/agents.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
- {
- "userId": "456e35c5-caf0-4d45-9084-b44a8ca717e4",
- "agentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
- "updatedTime": "2023-08-14T18:14:11.6833783Z",
- "createdTime": "2023-08-14T18:14:11.6829767Z",
- "editable": true,
- "id": "1273379c-4419-460a-b0a2-5695afd097f5"
- }
-]
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/users/d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc/agents.json b/tests/BotSharp.Plugin.PizzaBot/data/users/d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc/agents.json
deleted file mode 100644
index 32960f8c..00000000
--- a/tests/BotSharp.Plugin.PizzaBot/data/users/d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc/agents.json
+++ /dev/null
@@ -1,2 +0,0 @@
-[
-]
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/users/e465af5f-044f-414b-b670-92834929b96c/agents.json b/tests/BotSharp.Plugin.PizzaBot/data/users/e465af5f-044f-414b-b670-92834929b96c/agents.json
deleted file mode 100644
index 32960f8c..00000000
--- a/tests/BotSharp.Plugin.PizzaBot/data/users/e465af5f-044f-414b-b670-92834929b96c/agents.json
+++ /dev/null
@@ -1,2 +0,0 @@
-[
-]
\ No newline at end of file