Merge branch 'master' into lida_Dev
This commit is contained in:
commit
ffe66db8c1
|
|
@ -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 agent’s 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 agent’s 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 |
|
|
@ -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!;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
{
|
||||
"type": "planner",
|
||||
"field": "Sequential-Planner"
|
||||
"field": "Two-Stage-Planner"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ public partial class PlaywrightWebDriver
|
|||
}
|
||||
|
||||
// Release mouse button
|
||||
await Task.Delay(1000);
|
||||
await mouse.UpAsync();
|
||||
}
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in a new issue