Merge branch 'master' into lida_Dev

This commit is contained in:
AnonymousDotNet 2024-12-13 19:40:07 +08:00
commit ffe66db8c1
17 changed files with 91 additions and 68 deletions

View file

@ -4,7 +4,7 @@
This document aims to introduce the agent utility concept and provide an instruction on adding custom agent utilities in AI project “BotSharp”. We will start by explaining the mechanism of agent utility in [Section 2](#agent-utility). Then, we illustrate the custom agent utility setup and integration in [Section 3](#agent-utility-setup) and [Section 4](#agent-utility-integration), respectively. A use case will be demonstrated in [Section 5](#use-case-demo). We wrap up the document with a short summary.
## Agent Utility
The agent utility is a unique feature that can be integrated into agent to enhance its capability. Its core principle is that it can dynamically and seamlessly add extra prompts and add task-oriented functions (or tools) during conversation, without disrupting the agents primary purpose. In other words, the agent utility can perform extra tasks based on the context of conversation. Typical examples of agent utility include reading images/pdf, generating image, and sending http requests. [Fig 2.1.1](#agent-utility-example) demonstrates an example of these utilities. In this example, “Chatbot” is a simple agent to answer user questions and the utilities extend its capability to explain image content, generate requested image, and send a specific http request.
The agent utility is a unique feature that can be integrated into agent to enhance its capability. Its core principle is that it can dynamically and seamlessly add extra prompts and add task-oriented functions (or tools) during conversation, without disrupting the agents primary purpose. In other words, the agent utility can perform extra tasks based on the context of conversation. Typical examples of agent utility include reading images/pdf, generating image, and sending http requests. [Fig 2.1.1](#agent-utility-example) demonstrates an example of these utilities. In this example, “Chatbot” is a simple agent to answer user questions, and the utilities extend its capability to explain image content, generate requested image, and send a specific http request.
<div id="agent-utility-example">
<img src="assets/agent-utility/agent-utility-example.png" style="display: block; margin: auto;" />
@ -15,7 +15,7 @@ The agent utility is a unique feature that can be integrated into agent to enhan
In this section, we outline the steps to set up a custom agent utility. We start with the basic code structure and then add essential utility data, such as prompts and functions. The utility hooks are used to incorporate the utility into the agent. Finally, we give a brief overview of the utility implementation.
### Basic Code Structure
The basic code structure of a typical agent utility includes prompt/function data, hooks, and function implementation. We can add specific utility prompts and functions in different projects. Note that the agent “6745151e-6d46-4a02-8de4-1c4f21c7da95” is considered as a dedicated utility assistant, and every prompt and function can be optionally used as a utility. [Fig 3.1.1](#agent-utility-code-structure) presents the structure of prompt, function, hooks, and implementation of an http utility.
The basic code structure of a typical agent utility includes prompt/function data, hooks, and function implementation. We can add specific utility prompts and functions in different projects. Note that the agent **“6745151e-6d46-4a02-8de4-1c4f21c7da95”** is considered as a dedicated utility assistant, and every prompt and function can be optionally used as a utility. [Fig 3.1.1](#agent-utility-code-structure) presents the structure of prompt, function, hooks, and implementation of an http utility.
<div id="agent-utility-code-structure">
<img src="assets/agent-utility/agent-utility-code-structure.png" style="display: block; margin: auto;" />
@ -23,7 +23,7 @@ The basic code structure of a typical agent utility includes prompt/function dat
<br />
### Utility Data
For a typical agent utility, it is essential to add at least a prompt and a function. The prompt is added under the “templates” folder and its recommended name is “[function name].fn.liquid”, while the function is added under the “functions” folder and its recommended name is “[function name].json”. Once we compile the project, we can find the aggregated utility assistant folder at location: “\BotSharp\src\WebStarter\bin\Debug\net8.0\data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95”.
For a typical agent utility, it is essential to add at least one prompt and one function. The utility name is formatted as **“[plugin name].[utility name]”**, such as “http.http-handler”. The prompt is added under the “templates” folder and its recommended name is **util-[plugin name]-[function name].fn.liquid”**, while the function is added under the “functions” folder and its recommended name is **util-[plugin name]-[function name].json”**. Once we compile the project, we can find the aggregated utility assistant folder at location: **“\BotSharp\src\WebStarter\bin\Debug\net8.0\data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95”**.
### Utility Hooks
The utility hooks are used to connect the agent utility to the agent system. The code snippet below demonstrates an implementation of the http utility hook, where we define the utility name, prompts and functions. Note that each utility can be used across different agents.
@ -50,7 +50,7 @@ public class HttpHandlerPlugin : IBotSharpPlugin
}
```
The agent hook is used to append the utility prompt and function during the conversation. Note that the utility data is only allowed to be included in the context of conversation. The utility mechanism is implemented in the “OnAgentUtilityLoaded” hook, and it is invoked when we load any agent.
The agent hook is used to append the utility prompt and function during the conversation. **Note that the utility data is only allowed to be included in the context of conversation**. The utility mechanism is implemented in the **“OnAgentUtilityLoaded”** hook, and it is invoked when we load any agent.
```csharp
public async Task<Agent> LoadAgent(string id)
@ -128,7 +128,7 @@ Here we introduce a simple utility function implementation. The actual content d
```csharp
public class HandleHttpRequestFn : IFunctionCallback
{
public string Name => "handle_http_request";
public string Name => "util-http-handle_http_request";
public string Indication => "Handling http request";
private readonly IServiceProvider _services;
@ -344,12 +344,12 @@ Here we introduce the agent setup with utilities and inheritance. As we introduc
"profiles": [ "pizza" ],
"utilities": [
{
"name": "http_handler",
"name": "http.http-handler",
"functions": [
{ "name": "handle_http_request" }
{ "name": "util-http-handle_http_request" }
],
"templates": [
{ "name": "handle_http_request.fn" }
{ "name": "util-http-handle_http_request.fn" }
]
}
],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -5,6 +5,9 @@ public class ScheduleTaskArgs
[JsonPropertyName("cron_expression")]
public string Cron { get; set; } = null!;
[JsonPropertyName("less_than_60_seconds")]
public bool LessThan60Seconds { get; set; } = false;
[JsonPropertyName("title")]
public string Title { get; set; } = null!;

View file

@ -6,14 +6,15 @@ public class PluginDef
public string Name { get; set; }
public string Description { get; set; }
public string Assembly { get; set; }
[JsonPropertyName("is_core")]
public bool IsCore => Assembly == "BotSharp.Core" || Assembly == "BotSharp.Core.SideCar";
public bool IsCore => Assembly?.StartsWith("BotSharp.Core") == true;
[JsonPropertyName("icon_url")]
public string? IconUrl { get; set; }
[JsonPropertyName("agent_ids")]
public string[] AgentIds { get; set; } = new string[0];
public string[] AgentIds { get; set; } = [];
[JsonPropertyName("settings_name")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View file

@ -18,22 +18,37 @@ public class ScheduleTaskFn : IFunctionCallback
public async Task<bool> Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize<ScheduleTaskArgs>(message.FunctionArgs);
if (args.LessThan60Seconds)
{
message.Content = "Cron expression should not include seconds.";
return false;
}
var routing = _services.GetRequiredService<IRoutingContext>();
var user = _services.GetRequiredService<IUserIdentity>();
var crontabItem = new CrontabItem
{
Title = args.Title,
Description = args.Description,
Cron = args.Cron,
UserId = user.Id,
AgentId = routing.EntryAgentId,
ConversationId = routing.ConversationId,
Tasks = args.Tasks,
};
var db = _services.GetRequiredService<IBotSharpRepository>();
// var ret = db.UpsertCrontabItem(crontabItem);
if (string.IsNullOrEmpty(args.Cron))
{
var ret = db.DeleteCrontabItem(routing.ConversationId);
message.Content = $"Task schedule canceled result: {ret}";
}
else
{
var crontabItem = new CrontabItem
{
Title = args.Title,
Description = args.Description,
Cron = args.Cron,
UserId = user.Id,
AgentId = routing.EntryAgentId,
ConversationId = routing.ConversationId,
Tasks = args.Tasks,
};
var ret = db.UpsertCrontabItem(crontabItem);
message.Content = $"Task scheduled result: {ret}";
}
return true;
}

View file

@ -15,6 +15,7 @@
******************************************************************************/
using BotSharp.Abstraction.Repositories;
using BotSharp.Core.Infrastructures;
using Microsoft.Extensions.Logging;
namespace BotSharp.Core.Crontab.Services;
@ -45,14 +46,9 @@ public class CrontabService : ICrontabService
{
_logger.LogDebug($"ScheduledTimeArrived {item}");
var hooks = _services.GetServices<ICrontabHook>();
foreach(var hook in hooks)
{
await hook.OnCronTriggered(item);
}
/*await HookEmitter.Emit<ICrontabHook>(_services, async hook =>
await HookEmitter.Emit<ICrontabHook>(_services, async hook =>
await hook.OnCronTriggered(item)
);*/
);
await Task.Delay(1000 * 10);
}
}

View file

@ -48,9 +48,11 @@ public class CrontabWatcher : BackgroundService
{
try
{
// strip seconds from cron expression
item.Cron = string.Join(" ", item.Cron.Split(' ').TakeLast(5));
var schedule = CrontabSchedule.Parse(item.Cron, new CrontabSchedule.ParseOptions
{
IncludingSeconds = true // Ensure you account for seconds
IncludingSeconds = false // Ensure you account for seconds
});
// Get the current time

View file

@ -1,12 +1,16 @@
{
"name": "util-crontab-schedule_task",
"description": "Set up a scheduled task",
"description": "Set up or cancel a scheduled task",
"parameters": {
"type": "object",
"properties": {
"cron_expression": {
"type": "string",
"description": "cron expression include seconds"
"description": "cron expression. Set value as empty if user wants to cancel schedule."
},
"less_than_60_seconds": {
"type": "boolean",
"description": "whether schedule interval is less than 60 seconds"
},
"title": {
"type": "string",
@ -39,6 +43,6 @@
}
}
},
"required": [ "cron_expression", "title", "description", "to_do_list" ]
"required": [ "cron_expression", "include_seconds", "title", "description", "to_do_list" ]
}
}

View file

@ -1 +1,2 @@
Call schedule_task if user needs to set up a scheduled task with appropriate programming script and language type.
Call util-crontab-schedule_task if user needs to set up a scheduled task with appropriate programming script and language type.
Set cron_expression as empty if user wants to cancel schedule.

View file

@ -16,7 +16,7 @@
},
{
"type": "planner",
"field": "Sequential-Planner"
"field": "Two-Stage-Planner"
}
]
}

View file

@ -1,2 +1,3 @@
Analyze the user's problem. Which prerequisite task needs to be completed? Output the next step of routing instructions.
Check the job responsibilities of the routable Agent and do not transfer to an Agent that exceeds the scope of responsibility.
Check the job responsibilities of the routable Agent and do not transfer to an Agent that exceeds the scope of responsibility.
If the user request may require other tools or services, route to the planner agent.

View file

@ -1,7 +1,7 @@
{
"id": "3e75e818-a139-48a8-9e22-4662548c13a3",
"name": "Sequential-Planner",
"description": "Plan an ordered plan steps to execute some tasks in a predefined order by the user",
"description": "Plan an execution steps for the user complex task, especially if the tasks are in a predefined order by the user",
"type": "planning",
"createdDateTime": "2023-08-27T10:39:00Z",
"updatedDateTime": "2023-08-27T14:39:00Z",

View file

@ -5,15 +5,15 @@ internal static class SqlDriverHelper
internal static string GetDatabaseType(IServiceProvider services)
{
var settings = services.GetRequiredService<SqlDriverSetting>();
var dbType = "MySQL";
var dbType = "mysql";
if (!string.IsNullOrWhiteSpace(settings?.SqlServerConnectionString))
{
dbType = "SQL Server";
dbType = "sqlserver";
}
else if (!string.IsNullOrWhiteSpace(settings?.SqlLiteConnectionString))
{
dbType = "SQL Lite";
dbType = "sqllite";
}
return dbType;
}

View file

@ -17,38 +17,37 @@ public class SqlDriverCrontabHook : ICrontabHook
public async Task OnCronTriggered(CrontabItem item)
{
/*var conv = _services.GetRequiredService<IConversationService>();
conv.SetConversationId("abd9df25-2210-4e4d-80d7-48b6a3b905a8", []);
var conv = _services.GetRequiredService<IConversationService>();
conv.SetConversationId(item.ConversationId, []);
if (item.Language == "text")
{
var sidecar = _services.GetService<IConversationSideCar>();
var response = await sidecar.SendMessage(BuiltInAgentId.AIAssistant, item.Description, states: new List<MessageState>());
return;
}
else if (item.Language != "sql")
{
return;
}
_logger.LogWarning($"Crontab item triggered: {item.Title}. {item.Description}");
_logger.LogWarning($"Crontab item triggered: {item.Topic}. Run {item.Language}: {item.Script}");
var message = new RoleDialogModel(AgentRole.User, $"Run the query")
foreach (var task in item.Tasks)
{
FunctionName = "sql_select",
FunctionArgs = JsonSerializer.Serialize(new SqlStatement
if (task.Language == "text")
{
Statement = item.Script,
Reason = item.Description
})
};
var routing = _services.GetRequiredService<IRoutingService>();
routing.Context.Push("ec46f15b-8790-400f-a37f-1e7995b7d6e2");
await routing.InvokeFunction("sql_select", message);
var sidecar = _services.GetService<IConversationSideCar>();
var response = await sidecar.SendMessage(BuiltInAgentId.AIAssistant, $"{item.ExecutionResult}\r\n{task.Script}", states: new List<MessageState>());
}
else if (task.Language == "sql")
{
var message = new RoleDialogModel(AgentRole.User, $"Run the query")
{
FunctionName = "sql_select",
FunctionArgs = JsonSerializer.Serialize(new SqlStatement
{
Statement = task.Script,
Reason = item.Description
})
};
var routing = _services.GetRequiredService<IRoutingService>();
routing.Context.Push(BuiltInAgentId.SqlDriver);
await routing.InvokeFunction("sql_select", message);
item.ConversationId = conv.ConversationId;
item.AgentId = BuiltInAgentId.SqlDriver;
item.UserId = "41021346";
item.ExecutionResult = message.Content;*/
item.AgentId = BuiltInAgentId.SqlDriver;
item.UserId = "41021346";
item.ExecutionResult += message.Content + "\r\n";
}
}
}
}

View file

@ -113,6 +113,7 @@ public partial class PlaywrightWebDriver
}
// Release mouse button
await Task.Delay(1000);
await mouse.UpAsync();
}
else