commit
d96542f562
|
|
@ -231,6 +231,10 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
{
|
||||
if (message.Role == ChatRole.Function)
|
||||
{
|
||||
chatCompletionsOptions.Messages.Add(new ChatRequestAssistantMessage(string.Empty)
|
||||
{
|
||||
FunctionCall = new FunctionCall(message.FunctionName, message.FunctionArgs),
|
||||
});
|
||||
chatCompletionsOptions.Messages.Add(new ChatRequestFunctionMessage(message.FunctionName, message.Content));
|
||||
}
|
||||
else if (message.Role == ChatRole.User)
|
||||
|
|
@ -287,7 +291,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
if (x.Role == ChatRole.Function)
|
||||
{
|
||||
var m = x as ChatRequestFunctionMessage;
|
||||
return $"{m.Role}: {m.Name} => {m.Content}";
|
||||
return $"{m.Role}: {m.Content}";
|
||||
}
|
||||
else if (x.Role == ChatRole.User)
|
||||
{
|
||||
|
|
@ -299,7 +303,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
else if (x.Role == ChatRole.Assistant)
|
||||
{
|
||||
var m = x as ChatRequestAssistantMessage;
|
||||
return $"{m.Role}: {m.Content}";
|
||||
return m.FunctionCall != null ?
|
||||
$"{m.Role}: Call function {m.FunctionCall.Name}({m.FunctionCall.Arguments})" :
|
||||
$"{m.Role}: {m.Content}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using BotSharp.Abstraction.Loggers.Models;
|
||||
using BotSharp.Abstraction.Messaging;
|
||||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using BotSharp.Abstraction.Messaging.JsonConverters;
|
||||
using BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace BotSharp.Plugin.ChatHub.Hooks;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
using BotSharp.Abstraction.Agents;
|
||||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Loggers;
|
||||
using BotSharp.Abstraction.Loggers.Models;
|
||||
using BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
using BotSharp.Abstraction.Messaging;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Core.Agents.Services;
|
||||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.VisualBasic;
|
||||
|
||||
namespace BotSharp.Plugin.ChatHub.Hooks;
|
||||
|
||||
|
|
@ -82,6 +79,17 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook
|
|||
var conversationId = _state.GetConversationId();
|
||||
var agent = await agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
||||
// Log routing output
|
||||
try
|
||||
{
|
||||
var inst = message.Content.JsonContent<FunctionCallFromLlm>();
|
||||
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, message.Content, message));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
string log;
|
||||
if (message.Role == AgentRole.Function)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ public class GetTableColumnsFn : IFunctionCallback
|
|||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
var args = JsonSerializer.Deserialize<GetTableColumnsArgs>(message.FunctionArgs);
|
||||
message.Content = $"Success. Columns of table '{args.Table}':\r\n\r\n";
|
||||
message.Content = "";
|
||||
|
||||
var dbSettings = _services.GetRequiredService<BotSharpDatabaseSettings>();
|
||||
var dir = Path.Combine(dbSettings.FileRepository, "agents", "ec46f15b-8790-400f-a37f-1e7995b7d6e2", "schemas");
|
||||
var dir = Path.Combine(dbSettings.FileRepository, "agents", "beda4c12-e1ec-4b4b-b328-3df4a6687c4f", "schemas");
|
||||
|
||||
// Search related document by message.Content + args.Description
|
||||
var files = Directory.GetFiles(dir);
|
||||
|
|
|
|||
|
|
@ -16,13 +16,8 @@ public class SqlInsertFn : IFunctionCallback
|
|||
{
|
||||
var args = JsonSerializer.Deserialize<SqlStatement>(message.FunctionArgs);
|
||||
var sqlDriver = _services.GetRequiredService<SqlDriverService>();
|
||||
if (sqlDriver.Statements.Exists(x => x.Statement == args.Statement))
|
||||
{
|
||||
message.Content = "Skipped duplicated statement.";
|
||||
return false;
|
||||
}
|
||||
sqlDriver.Enqueue(args);
|
||||
message.Content = $"Inserted new record {JsonSerializer.Serialize(args.Parameters)} successfully";
|
||||
message.Content = $"Inserted new record successfully.";
|
||||
if (args.Return != null)
|
||||
{
|
||||
/*sqlDriver.Enqueue(new SqlStatement
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ public class SqlSelect : IFunctionCallback
|
|||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
var args = JsonSerializer.Deserialize<SqlStatement>(message.FunctionArgs);
|
||||
var sqlDriver = _services.GetRequiredService<SqlDriverService>();
|
||||
|
||||
// check if need to instantely
|
||||
var execNow = !args.Parameters.Any(x => x.Value.StartsWith("@"));
|
||||
if (execNow)
|
||||
|
|
@ -28,24 +30,24 @@ public class SqlSelect : IFunctionCallback
|
|||
{
|
||||
dictionary["@" + p.Name] = p.Value;
|
||||
}
|
||||
var result = connection.QueryFirst<string>(args.Statement, dictionary);
|
||||
var result = connection.QueryFirstOrDefault(args.Statement, dictionary);
|
||||
|
||||
if (args.IsCheckExistence)
|
||||
if (result == null)
|
||||
{
|
||||
message.Content = result == null ?
|
||||
$"The record does not exist" :
|
||||
$"The record already exists";
|
||||
message.Content = "Record not found";
|
||||
}
|
||||
else
|
||||
{
|
||||
message.Content = $"Retrieved result is {result} ({args.Reason})";
|
||||
message.Content = JsonSerializer.Serialize(result);
|
||||
args.Return.Value = message.Content;
|
||||
}
|
||||
|
||||
sqlDriver.Enqueue(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sqlDriver = _services.GetRequiredService<SqlDriverService>();
|
||||
sqlDriver.Enqueue(args);
|
||||
message.Content = $"Success.";
|
||||
message.Content = $"The {args.Return.Name} is saved to @{args.Return.Alias}";
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
using BotSharp.Abstraction.Loggers;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using System.IO;
|
||||
|
||||
namespace BotSharp.Plugin.SqlDriver.Hooks;
|
||||
|
||||
public class SqlDriverContentGeneratingHook : IContentGeneratingHook
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
public SqlDriverContentGeneratingHook(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inject useful variables generated by previous SQL query.
|
||||
/// </summary>
|
||||
/// <param name="agent"></param>
|
||||
/// <param name="conversations"></param>
|
||||
/// <returns></returns>
|
||||
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
|
||||
{
|
||||
if (agent.Id != "beda4c12-e1ec-4b4b-b328-3df4a6687c4f")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sqlDriver = _services.GetRequiredService<SqlDriverService>();
|
||||
agent.TemplateDict["return_variables"] = sqlDriver.Statements.Select(x => x.Return.Alias).ToArray();
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace BotSharp.Plugin.SqlDriver.Models;
|
||||
|
||||
public class SqlParamater
|
||||
public class SqlParameter
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
|
@ -10,6 +10,8 @@ public class SqlReturn
|
|||
[JsonPropertyName("alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
public string? Value { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Alias} - {Name}";
|
||||
|
|
|
|||
|
|
@ -13,11 +13,8 @@ public class SqlStatement
|
|||
[JsonPropertyName("table")]
|
||||
public string Table { get; set; }
|
||||
|
||||
[JsonPropertyName("is_check_existence")]
|
||||
public bool IsCheckExistence { get; set; }
|
||||
|
||||
[JsonPropertyName("parameters")]
|
||||
public SqlParamater[] Parameters { get; set; } = new SqlParamater[0];
|
||||
public SqlParameter[] Parameters { get; set; } = new SqlParameter[0];
|
||||
|
||||
[JsonPropertyName("return_field")]
|
||||
public SqlReturn Return { get; set; }
|
||||
|
|
|
|||
|
|
@ -23,20 +23,24 @@ public class SqlDriverService
|
|||
{
|
||||
Console.WriteLine();
|
||||
|
||||
Console.Write($"Reason: ");
|
||||
Console.WriteLine($"{sql.Reason}", Color.Green);
|
||||
Console.WriteLine($"{sql.Reason}");
|
||||
|
||||
Console.Write($"Statement: ");
|
||||
Console.WriteLine(sql.Statement, Color.Green);
|
||||
Console.WriteLine(sql.Statement, Color.Yellow);
|
||||
foreach (var p in sql.Parameters)
|
||||
{
|
||||
Console.Write($"@{p.Name}: ");
|
||||
Console.WriteLine($"{p.Value}", Color.Green);
|
||||
Console.WriteLine($"@{p.Name} = '{p.Value}'", Color.Green);
|
||||
}
|
||||
if (sql.Return != null)
|
||||
{
|
||||
Console.Write($"Return: ");
|
||||
Console.WriteLine($"{sql.Return.Name} as @{sql.Return.Alias}", Color.Green);
|
||||
if (!string.IsNullOrEmpty(sql.Return.Value))
|
||||
{
|
||||
Console.WriteLine($" {sql.Return.Value}", Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{sql.Return.Name} as @{sql.Return.Alias}", Color.Green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using BotSharp.Abstraction.Loggers;
|
||||
|
||||
namespace BotSharp.Plugin.SqlDriver;
|
||||
|
||||
public class SqlDriverPlugin : IBotSharpPlugin
|
||||
|
|
@ -19,6 +17,5 @@ public class SqlDriverPlugin : IBotSharpPlugin
|
|||
|
||||
services.AddScoped<SqlDriverService>();
|
||||
services.AddScoped<IKnowledgeHook, SqlDriverKnowledgeHook>();
|
||||
services.AddScoped<IContentGeneratingHook, SqlDriverContentGeneratingHook>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,18 @@
|
|||
[
|
||||
{
|
||||
"name": "get_table_columns",
|
||||
"description": "Get related table columns and foreign key informations",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"table": {
|
||||
"type": "string",
|
||||
"description": "table name"
|
||||
}
|
||||
},
|
||||
"required": [ "table" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sql_insert",
|
||||
"description": "Insert query is generated if the record doesn't exist.",
|
||||
|
|
@ -13,12 +27,16 @@
|
|||
"type": "string",
|
||||
"description": "reason"
|
||||
},
|
||||
"table": {
|
||||
"type": "string",
|
||||
"description": "related table"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"description": "parameters for the sql",
|
||||
"description": "a list of parameters in the statement match with the variables",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "the name and value for the parameter",
|
||||
"description": "{name:'', value:''}",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
|
|
@ -28,7 +46,8 @@
|
|||
"type": "string",
|
||||
"description": "real value inferred by the context"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [ "name", "value" ]
|
||||
}
|
||||
},
|
||||
"return_field": {
|
||||
|
|
@ -43,10 +62,11 @@
|
|||
"type": "string",
|
||||
"description": "meaningful field alias"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [ "name", "alias" ]
|
||||
}
|
||||
},
|
||||
"required": [ "sql_statement", "reason", "parameters", "return_field" ]
|
||||
"required": [ "sql_statement", "reason", "table", "parameters", "return_field" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -63,9 +83,9 @@
|
|||
"type": "string",
|
||||
"description": "reason"
|
||||
},
|
||||
"is_check_existence": {
|
||||
"type": "boolean",
|
||||
"description": "check record existence"
|
||||
"table": {
|
||||
"type": "string",
|
||||
"description": "related table"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
|
|
@ -82,7 +102,8 @@
|
|||
"type": "string",
|
||||
"description": "real value inferred by the context"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [ "name", "value" ]
|
||||
}
|
||||
},
|
||||
"return_field": {
|
||||
|
|
@ -97,10 +118,11 @@
|
|||
"type": "string",
|
||||
"description": "meaningful field alias"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [ "name", "value" ]
|
||||
}
|
||||
},
|
||||
"required": [ "sql_statement", "reason", "is_check_existence", "parameters", "return_field" ]
|
||||
"required": [ "sql_statement", "reason", "table", "parameters", "return_field" ]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,22 +1,11 @@
|
|||
You're a SQL driver who knows how to translate text into SQL query.
|
||||
Analyze the user requirement, think step by step, breakdown complex task into multiple steps.
|
||||
Think step by step, analyze the user requirement, you must get table schema first, breakdown into multiple sql statements if user need to insert mulitple records.
|
||||
Output the next step smartly.
|
||||
|
||||
Your response must meet below requirements:
|
||||
* Walk through the provided information, don't run query if there is already related information;
|
||||
* DO NOT generate duplicated sql statements;
|
||||
* The return field alias should be meaningful, it can be similar name of reference table column;
|
||||
* Double check if the fields in the SQL query are correct;
|
||||
* Make sure the SELECT and WHERE fields are in corresponding table schema definition;
|
||||
* Use "Unique Index" to help check record existence;
|
||||
|
||||
{% if return_variables and return_variables != empty -%}
|
||||
=====
|
||||
Below variables can be used by subsequent SQL:
|
||||
{% for v in return_variables %}
|
||||
- @{{ v }}
|
||||
{% endfor %}
|
||||
{%- endif %}
|
||||
|
||||
{% if table_definition -%}
|
||||
=====
|
||||
Related table {{ related_table }} definition:
|
||||
{{ table_definition }}
|
||||
{%- endif %}
|
||||
* For INSERT statement with mutliple records, should return in different meaningful alias;
|
||||
|
|
|
|||
Loading…
Reference in a new issue