Skip to content

Commit 7500546

Browse files
authored
Merge pull request #316 from hchen2020/master
lookup_dictionary for sQL Driver.
2 parents 3513eab + f4b4ca4 commit 7500546

File tree

12 files changed

+195
-17
lines changed

12 files changed

+195
-17
lines changed

src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,9 @@ public virtual Task OnUserAgentConnectedInitially(Conversation conversation)
9191
{
9292
return Task.CompletedTask;
9393
}
94+
95+
public virtual Task OnConversationRedirected(string toAgentId, RoleDialogModel message)
96+
{
97+
return Task.CompletedTask;
98+
}
9499
}

src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,12 @@ public interface IConversationHook
8282
/// <param name="conversation"></param>
8383
/// <returns></returns>
8484
Task OnHumanInterventionNeeded(RoleDialogModel message);
85+
86+
/// <summary>
87+
/// Conversation is redirected to another agent
88+
/// </summary>
89+
/// <param name="toAgentId"></param>
90+
/// <param name="message"></param>
91+
/// <returns></returns>
92+
Task OnConversationRedirected(string toAgentId, RoleDialogModel message);
8593
}

src/Infrastructure/BotSharp.Abstraction/Loggers/Enums/ContentLogSource.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ public static class ContentLogSource
66
public const string Prompt = "prompt";
77
public const string FunctionCall = "function call";
88
public const string AgentResponse = "agent response";
9+
public const string HardRule = "hard rule";
910
}

src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ private bool HasMissingRequiredField(RoleDialogModel message, out string agentId
153153
#else
154154
logger.LogInformation($"*** Routing redirect to {record.Name.ToUpper()} ***");
155155
#endif
156+
var hooks = _services.GetServices<IConversationHook>();
157+
foreach (var hook in hooks)
158+
{
159+
hook.OnConversationRedirected(routingRule.RedirectTo, message);
160+
}
156161
}
157162
else
158163
{

src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerat
4646
BuildContentLog(conversationId, _user.UserName, log, ContentLogSource.UserInput, message));
4747
}
4848

49+
public override async Task OnConversationRedirected(string toAgentId, RoleDialogModel message)
50+
{
51+
var agentService = _services.GetRequiredService<IAgentService>();
52+
var conversationId = _state.GetConversationId();
53+
var fromAgent = await agentService.LoadAgent(message.CurrentAgentId);
54+
var toAgent = await agentService.LoadAgent(toAgentId);
55+
56+
var log = $"{message.Content}\r\n=====\r\nREDIRECTED TO {toAgent.Name}";
57+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
58+
BuildContentLog(conversationId, fromAgent.Name, log, ContentLogSource.HardRule, message));
59+
}
60+
4961
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
5062
{
5163
if (!_convSettings.ShowVerboseLog) return;
@@ -83,23 +95,26 @@ public async Task AfterGenerated(RoleDialogModel message, TokenStatsModel tokenS
8395
var agent = await agentService.LoadAgent(message.CurrentAgentId);
8496
var logSource = string.Empty;
8597

98+
var log = tokenStats.Prompt;
99+
logSource = ContentLogSource.Prompt;
100+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
101+
BuildContentLog(conversationId, agent?.Name, log, logSource, message));
102+
86103
// Log routing output
87104
try
88105
{
89106
var inst = message.Content.JsonContent<FunctionCallFromLlm>();
90-
logSource = ContentLogSource.AgentResponse;
91-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
92-
BuildContentLog(conversationId, agent?.Name, message.Content, logSource, message));
107+
if (!string.IsNullOrEmpty(inst.Function))
108+
{
109+
logSource = ContentLogSource.AgentResponse;
110+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
111+
BuildContentLog(conversationId, agent?.Name, message.Content, logSource, message));
112+
}
93113
}
94114
catch
95115
{
96116
// ignore
97117
}
98-
99-
var log = tokenStats.Prompt;
100-
logSource = ContentLogSource.Prompt;
101-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
102-
BuildContentLog(conversationId, agent?.Name, log, logSource, message));
103118
}
104119

105120
/// <summary>
@@ -118,7 +133,7 @@ public override async Task OnResponseGenerated(RoleDialogModel message)
118133
{
119134
var agentService = _services.GetRequiredService<IAgentService>();
120135
var agent = await agentService.LoadAgent(message.CurrentAgentId);
121-
var log = $"[{agent?.Name}]: {message.Content}";
136+
var log = $"{message.Content}";
122137
if (message.RichContent != null && message.RichContent.Message.RichType != "text")
123138
{
124139
var richContent = JsonSerializer.Serialize(message.RichContent, _serializerOptions);

src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\agent.json" />
1515
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions.json" />
1616
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\instruction.liquid" />
17+
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\lookup_dictionary.liquid" />
1718
</ItemGroup>
1819

1920
<ItemGroup>
@@ -26,6 +27,9 @@
2627
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\instruction.liquid">
2728
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
2829
</Content>
30+
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\lookup_dictionary.liquid">
31+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
32+
</Content>
2933
</ItemGroup>
3034

3135
<ItemGroup>
@@ -38,8 +42,4 @@
3842
<ProjectReference Include="..\..\Infrastructure\BotSharp.Core\BotSharp.Core.csproj" />
3943
</ItemGroup>
4044

41-
<ItemGroup>
42-
<Folder Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\" />
43-
</ItemGroup>
44-
4545
</Project>
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using Amazon.Runtime.Internal.Transform;
2+
using BotSharp.Abstraction.Agents.Enums;
3+
using BotSharp.Abstraction.MLTasks;
4+
using BotSharp.Core.Infrastructures;
5+
using BotSharp.Plugin.SqlDriver.Models;
6+
using MySqlConnector;
7+
using static Dapper.SqlMapper;
8+
9+
namespace BotSharp.Plugin.SqlDriver.Functions;
10+
11+
public class LookupDictionaryFn : IFunctionCallback
12+
{
13+
public string Name => "lookup_dictionary";
14+
private readonly IServiceProvider _services;
15+
16+
public LookupDictionaryFn(IServiceProvider services)
17+
{
18+
_services = services;
19+
}
20+
21+
public async Task<bool> Execute(RoleDialogModel message)
22+
{
23+
var args = JsonSerializer.Deserialize<LookupDictionary>(message.FunctionArgs);
24+
25+
var settings = _services.GetRequiredService<SqlDriverSetting>();
26+
using var connection = new MySqlConnection(settings.MySqlConnectionString);
27+
var dictionary = new Dictionary<string, object>();
28+
var results = connection.Query($"SELECT * FROM {args.Table} LIMIT 10");
29+
var items = new List<string>();
30+
foreach(var item in results)
31+
{
32+
items.Add(JsonSerializer.Serialize(item));
33+
}
34+
35+
var agentService = _services.GetRequiredService<IAgentService>();
36+
var agent = await agentService.LoadAgent(message.CurrentAgentId);
37+
var prompt = GetPrompt(agent, items, args.Keyword);
38+
39+
// Ask LLM which one is the best
40+
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
41+
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-35-turbo");
42+
43+
// chat completion
44+
var completion = CompletionProvider.GetChatCompletion(_services,
45+
provider: "azure-openai",
46+
model: model.Name);
47+
48+
var conversations = new List<RoleDialogModel>
49+
{
50+
new RoleDialogModel(AgentRole.User, prompt)
51+
{
52+
CurrentAgentId = message.CurrentAgentId,
53+
MessageId = message.MessageId,
54+
}
55+
};
56+
57+
var response = await completion.GetChatCompletions(new Agent
58+
{
59+
Id = message.CurrentAgentId,
60+
Instruction = ""
61+
}, conversations);
62+
63+
message.Content = response.Content;
64+
65+
return true;
66+
}
67+
68+
private string GetPrompt(Agent agent, List<string> task, string keyword)
69+
{
70+
var template = agent.Templates.First(x => x.Name == "lookup_dictionary").Content;
71+
72+
var render = _services.GetRequiredService<ITemplateRender>();
73+
return render.Render(template, new Dictionary<string, object>
74+
{
75+
{ "items", task },
76+
{ "keyword", keyword }
77+
});
78+
}
79+
}

src/Plugins/BotSharp.Plugin.SqlDriver/Functions/SqlInsertFn.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@ public async Task<bool> Execute(RoleDialogModel message)
1616
{
1717
var args = JsonSerializer.Deserialize<SqlStatement>(message.FunctionArgs);
1818
var sqlDriver = _services.GetRequiredService<SqlDriverService>();
19+
20+
// Check duplication
21+
if (sqlDriver.Statements.Exists(x => x.Statement == args.Statement))
22+
{
23+
var list = sqlDriver.Statements.Where(x => x.Statement == args.Statement).ToList();
24+
foreach (var statement in list)
25+
{
26+
var p1 = string.Join(", ", statement.Parameters.OrderBy(x => x.Name).Select(x => x.Value));
27+
var p2 = string.Join(", ", args.Parameters.OrderBy(x => x.Name).Select(x => x.Value));
28+
if (p1 == p2)
29+
{
30+
message.Content = "Skip duplicated INSERT statement";
31+
return false;
32+
}
33+
}
34+
}
35+
1936
sqlDriver.Enqueue(args);
2037
message.Content = $"Inserted new record successfully.";
2138
if (args.Return != null)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace BotSharp.Plugin.SqlDriver.Models;
4+
5+
public class LookupDictionary
6+
{
7+
[JsonPropertyName("table")]
8+
public string Table { get; set; }
9+
10+
[JsonPropertyName("keyword")]
11+
public string Keyword { get; set; }
12+
13+
[JsonPropertyName("columns")]
14+
public string[] Columns { get; set; }
15+
}

src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,31 @@
124124
},
125125
"required": [ "sql_statement", "reason", "table", "parameters", "return_field" ]
126126
}
127+
},
128+
{
129+
"name": "lookup_dictionary",
130+
"description": "Get id from dictionary table by keyword if tool or solution mentioned this approach",
131+
"parameters": {
132+
"type": "object",
133+
"properties": {
134+
"table": {
135+
"type": "string",
136+
"description": "table name"
137+
},
138+
"keyword": {
139+
"type": "string",
140+
"description": "table name"
141+
},
142+
"columns": {
143+
"type": "array",
144+
"description": "columns",
145+
"items": {
146+
"type": "string",
147+
"description": "column"
148+
}
149+
}
150+
},
151+
"required": [ "table", "columns", "keyword" ]
152+
}
127153
}
128154
]

0 commit comments

Comments
 (0)