UnmatchedAgent

This commit is contained in:
Haiping Chen 2024-01-06 16:24:22 -06:00
parent 4299a67057
commit cdae1235da
41 changed files with 233 additions and 38 deletions

View file

@ -77,6 +77,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.TelegramBot
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Logger", "src\Infrastructure\BotSharp.Logger\BotSharp.Logger.csproj", "{5CA3335E-E6AD-46FD-B277-29BBC3A16500}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.HttpHandler", "src\Plugins\BotSharp.Plugin.HttpHandler\BotSharp.Plugin.HttpHandler.csproj", "{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -293,6 +295,14 @@ Global
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|Any CPU.Build.0 = Release|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|x64.ActiveCfg = Release|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|x64.Build.0 = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|x64.ActiveCfg = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|x64.Build.0 = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|Any CPU.Build.0 = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|x64.ActiveCfg = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -331,6 +341,7 @@ Global
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8} = {64264688-0F5C-4AB0-8F2B-B59B717CCE00}
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E} = {64264688-0F5C-4AB0-8F2B-B59B717CCE00}
{5CA3335E-E6AD-46FD-B277-29BBC3A16500} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}

View file

@ -53,6 +53,12 @@ public class RoleDialogModel : ITrackableMessage
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public bool StopCompletion { get; set; }
/// <summary>
/// Router routed to a wrong agent.
/// Set this flag as True will force router to re-route current request to a new agent.
/// </summary>
public bool UnmatchedAgent { get; set; }
public FunctionCallFromLlm Instruction { get; set; }
private RoleDialogModel()

View file

@ -15,6 +15,13 @@ public class FunctionCallFromLlm : RoutingArgs
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public bool ExecutingDirectly { get; set; }
/// <summary>
/// Router routed to a wrong agent.
/// Set this flag as True will force router to re-route current request to a new agent.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public bool UnmatchedAgent { get; set; }
public override string ToString()
{
var route = string.IsNullOrEmpty(AgentName) ? "" : $"<Route to {AgentName.ToUpper()} because {Reason}>";

View file

@ -9,6 +9,6 @@ namespace BotSharp.Abstraction.Planning;
public interface IPlaner
{
Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId);
Task<bool> AgentExecuting(FunctionCallFromLlm inst, RoleDialogModel message);
Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message);
Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message);
Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message);
}

View file

@ -8,5 +8,11 @@ public interface IBotSharpPlugin
string Name => "";
string Description => "";
string IconUrl => "https://avatars.githubusercontent.com/u/44989469?s=200&v=4";
/// <summary>
/// Has build-in agent profile with this plugin
/// </summary>
bool WithAgent => false;
void RegisterDI(IServiceCollection services, IConfiguration config);
}

View file

@ -8,4 +8,7 @@ public class PluginDef
public string Assembly { get; set; }
[JsonPropertyName("icon_url")]
public string IconUrl { get; set; }
[JsonPropertyName("with_agent")]
public bool WithAgent { get; set; }
}

View file

@ -18,4 +18,9 @@ public class RoutingItem
[JsonPropertyName("optional_fields")]
public List<ParameterPropertyDef> OptionalFields { get; set; } = new List<ParameterPropertyDef>();
public override string ToString()
{
return Name;
}
}

View file

@ -67,7 +67,7 @@ public class HFPlanner : IPlaner
return inst;
}
public async Task<bool> AgentExecuting(FunctionCallFromLlm inst, RoleDialogModel message)
public async Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message)
{
if (!string.IsNullOrEmpty(inst.AgentName))
{
@ -82,7 +82,7 @@ public class HFPlanner : IPlaner
return true;
}
public async Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
public async Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message)
{
var context = _services.GetRequiredService<RoutingContext>();
context.Empty();

View file

@ -76,7 +76,7 @@ public class NaivePlanner : IPlaner
return inst;
}
public async Task<bool> AgentExecuting(FunctionCallFromLlm inst, RoleDialogModel message)
public async Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message)
{
// Set user content as Planner's question
message.FunctionName = inst.Function;
@ -85,10 +85,24 @@ public class NaivePlanner : IPlaner
return true;
}
public async Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
public async Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message)
{
var context = _services.GetRequiredService<RoutingContext>();
context.Empty();
if (inst.UnmatchedAgent)
{
var unmatchedAgentId = context.GetCurrentAgentId();
// Exclude the wrong routed agent
var agents = router.TemplateDict["routing_agents"] as RoutingItem[];
router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray();
// Handover to Router;
context.Pop();
}
else
{
context.Empty();
}
return true;
}

View file

@ -54,7 +54,8 @@ public class PluginLoader
Name = name,
Description = module.Description,
Assembly = assemblyName,
IconUrl = module.IconUrl
IconUrl = module.IconUrl,
WithAgent = module.WithAgent,
});
Console.Write($"Loaded plugin ");
Console.Write(name, Color.Green);

View file

@ -50,6 +50,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
var response = _dialogs.Last();
inst.Response = response.Content;
inst.UnmatchedAgent = response.UnmatchedAgent;
return true;
}

View file

@ -59,8 +59,18 @@ 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
if (!message.StopCompletion)
else if (!message.StopCompletion)
{
var routing = _services.GetRequiredService<RoutingContext>();

View file

@ -98,12 +98,12 @@ public partial class RoutingService : IRoutingService
#else
_logger.LogInformation($"*** Next Instruction *** {inst}");
#endif
await planner.AgentExecuting(inst, message);
await planner.AgentExecuting(_router, inst, message);
// Handle instruction by Executor
response = await executor.Execute(this, inst, message, dialogs);
await planner.AgentExecuted(inst, response);
await planner.AgentExecuted(_router, inst, response);
}
return response;

View file

@ -1,7 +1,5 @@
using BotSharp.Abstraction.Messaging.JsonConverters;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
namespace BotSharp.OpenAPI;

View file

@ -10,6 +10,8 @@ public class ChatHubPlugin : IBotSharpPlugin
{
public string Name => "Chat Hub";
public string Description => "A communication channel connects agents and users in real-time.";
public string IconUrl => "https://media.zeemly.com/media/product/chatrandom.png";
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
// Register hooks

View file

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>$(LangVersion)</LangVersion>
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
<GenerateDocumentationFile>$(GenerateDocumentationFile)</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Infrastructure\BotSharp.Core\BotSharp.Core.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,16 @@
using Microsoft.Extensions.Configuration;
namespace BotSharp.Plugin.HttpHandler;
public class HttpHandlerPlugin : IBotSharpPlugin
{
public string Name => "HTTP Handler";
public string Description => "Empower agent to handle HTTP request in RESTful API or GraphQL";
public string IconUrl => "https://lirp.cdn-website.com/6f8d6d8a/dms3rep/multi/opt/API_Icon-640w.png";
public bool WithAgent => true;
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
}
}

View file

@ -0,0 +1,14 @@
global using System;
global using System.Collections.Generic;
global using System.Text;
global using BotSharp.Abstraction.Conversations;
global using BotSharp.Abstraction.Plugins;
global using System.Text.Json;
global using BotSharp.Abstraction.Conversations.Models;
global using System.Threading.Tasks;
global using BotSharp.Abstraction.Functions;
global using BotSharp.Abstraction.Agents.Models;
global using BotSharp.Abstraction.Templating;
global using Microsoft.Extensions.DependencyInjection;
global using System.Linq;
global using BotSharp.Abstraction.Utilities;

View file

@ -0,0 +1,9 @@
{
"name": "HTTP Handler",
"description": "Use Web API to interact with other systems to obtain or update data.",
"createdDateTime": "2024-01-06T00:00:00Z",
"updatedDateTime": "2024-01-06T00:00:00Z",
"id": "87c458fc-ec5f-40ae-8ed6-05dda8a07523",
"allowRouting": true,
"isPublic": true
}

View file

@ -0,0 +1 @@
You are an HTTP handler and know how to use Open API to interact with other systems.

View file

@ -28,8 +28,7 @@ public class SearchKnowledgesFn : IFunctionCallback
if (string.IsNullOrEmpty(knowledge))
{
message.Content = "Can't find any relevant data in local knowledge base.";
var routingCtx = _services.GetRequiredService<RoutingContext>();
routingCtx.Pop();
message.UnmatchedAgent = true;
}
return true;

View file

@ -6,6 +6,9 @@ public class KnowledgeBasePlugin : IBotSharpPlugin
{
public string Name => "Knowledge Base";
public string Description => "Embedding private data and feed them into LLM in the conversation.";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/9592/9592995.png";
public bool WithAgent => true;
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
var settings = new KnowledgeBaseSettings();

View file

@ -0,0 +1,9 @@
{
"name": "Knowledge Base",
"description": "Local knowledge base, providing relevant answers or background knowledge to help handle user questions.",
"createdDateTime": "2024-01-02T00:00:00Z",
"updatedDateTime": "2024-01-02T00:00:00Z",
"id": "f5679799-ba89-4fef-936a-bcc311e5f14d",
"allowRouting": true,
"isPublic": true
}

View file

@ -0,0 +1,16 @@
[
{
"name": "search_knowledges",
"description": "Retrieve relevant knowledges",
"parameters": {
"type": "object",
"properties": {
"question": {
"type": "string",
"description": "User question"
}
},
"required": ["question"]
}
}
]

View file

@ -0,0 +1 @@
You are a local knowledge base that retrieves the most relevant answers to certain questions.

View file

@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LLamaSharp" Version="0.8.1" />
<PackageReference Include="LLamaSharp" Version="0.9.1" />
</ItemGroup>
<ItemGroup>

View file

@ -20,7 +20,9 @@ public class TextEmbeddingProvider : ITextEmbedding
if (_embedder == null)
{
var path = Path.Combine(_settings.ModelDir, _settings.DefaultModel);
_embedder = new LLamaEmbedder(new ModelParams(path));
var @params = new ModelParams(path);
using var weights = LLamaWeights.LoadFromFile(@params);
_embedder = new LLamaEmbedder(weights, @params);
}
return Task.FromResult(_embedder.GetEmbeddings(text));

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
@ -12,12 +12,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Playwright" Version="1.39.0" />
</ItemGroup>
<ItemGroup>
<Compile Remove="agents\**" />
<EmbeddedResource Remove="agents\**" />
<None Remove="agents\**" />
</ItemGroup>
<ItemGroup>
<None Remove="README.md" />

View file

@ -20,6 +20,10 @@ public class PlaywrightInstance : IDisposable
{
Headless = false,
Channel = "chrome",
Args = new[]
{
"--start-maximized"
}
});
}
}

View file

@ -8,7 +8,10 @@ public partial class PlaywrightWebDriver
if (!string.IsNullOrEmpty(url))
{
var page = await _instance.Browser.NewPageAsync();
var page = await _instance.Browser.NewPageAsync(new BrowserNewPageOptions
{
ViewportSize = ViewportSize.NoViewport
});
_instance.SetPage(page);
var response = await page.GotoAsync(url);
}

View file

@ -7,7 +7,9 @@ namespace BotSharp.Plugin.Playwrights;
public class WebDriverPlugin : IBotSharpPlugin
{
public string Name => "Web Driver";
public string Description => "Manipulate web browser in automation tools.";
public string Description => "Empower agent to manipulate web browser in automation tools.";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/8576/8576378.png";
public bool WithAgent => true;
public void RegisterDI(IServiceCollection services, IConfiguration config)
{

View file

@ -1,5 +1,5 @@
{
"name": "Web Browser",
"name": "Web Driver",
"description": "Perform a specific action on a web browser",
"createdDateTime": "2024-01-02T00:00:00Z",
"updatedDateTime": "2024-01-02T00:00:00Z",

View file

@ -14,8 +14,8 @@
}
},
{
"name": "click_html_element",
"description": "Click the html element in a web page.",
"name": "click_button",
"description": "Click a button in a web page.",
"parameters": {
"type": "object",
"properties": {
@ -27,22 +27,50 @@
"required": ["element_name"]
}
},
{
"name": "extract_data_from_page",
"description": "Extract data from current web page.",
"parameters": {
"type": "object",
"properties": {
"question": {
"type": "string",
"description": "the information user wants to know"
}
},
"required": ["question"]
}
},
{
"name": "input_user_text",
"description": "Input text in input box of web page when user requests.",
"description": "Input non-sensitive text in current web page.",
"parameters": {
"type": "object",
"properties": {
"element_name": {
"type": "string",
"description": "the html element name."
"description": "the html input box element name."
},
"input_text": {
"type": "string",
"description": "user input."
"description": "non-sensitive text user provided."
}
},
"required": ["element_name", "input_text"]
}
},
{
"name": "input_user_password",
"description": "Input password in current web page",
"parameters": {
"type": "object",
"properties": {
"password": {
"type": "string",
"description": "user password"
}
},
"required": ["password"]
}
}
]

View file

@ -1,2 +1,8 @@
You are a web browser that can manipulate web elements through automated tools like Playwright and Selenium.
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.
Additional response requirements:
* Call function input_user_password if user wants to input password.

View file

@ -0,0 +1,4 @@
{{ content }}
=== According to above text ===
Find the answer of "{{ question }}"

View file

@ -1,6 +1,5 @@
{{ html_content }}
=== According to above HTML ===
You're using Playwright selector syntax.
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.

View file

@ -35,10 +35,11 @@
<PackageReference Include="BotSharp.Plugin.RoutingSpeeder" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.Qdrant" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.WeChat" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.HttpHandler" Version="$(BotSharpVersion)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="LLamaSharp.Backend.Cuda11" Version="0.8.1" />
<PackageReference Include="LLamaSharp.Backend.Cuda11" Version="0.9.1" />
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="2.16.0" />
</ItemGroup>
@ -64,6 +65,7 @@
<ProjectReference Include="..\Plugins\BotSharp.Plugin.ChatHub\BotSharp.Plugin.ChatHub.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.TelegramBots\BotSharp.Plugin.TelegramBots.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.WebDriver\BotSharp.Plugin.WebDriver.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.HttpHandler\BotSharp.Plugin.HttpHandler.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -168,6 +168,7 @@
// "BotSharp.Plugin.TelegramBots",
// "BotSharp.Plugin.RoutingSpeeder",
"BotSharp.Plugin.WebDriver",
"BotSharp.Plugin.HttpHandler",
"BotSharp.Plugin.PizzaBot"
]
}

View file

@ -14,11 +14,8 @@
</ItemGroup>
<ItemGroup>
<Compile Remove="agents\**" />
<Compile Remove="documents\**" />
<EmbeddedResource Remove="agents\**" />
<EmbeddedResource Remove="documents\**" />
<None Remove="agents\**" />
<None Remove="documents\**" />
</ItemGroup>

View file

@ -7,6 +7,8 @@ public class PizzaBotPlugin : IBotSharpPlugin
{
public string Name => "Pizza AI Assistant";
public string Description => "An example of an enterprise-grade AI Chatbot.";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/6978/6978255.png";
public bool WithAgent => true;
public void RegisterDI(IServiceCollection services, IConfiguration config)
{