From 3c1c599b60628c51d189d2e25680296ee92f60ea Mon Sep 17 00:00:00 2001
From: Jicheng Lu <103353@smsassist.com>
Date: Wed, 20 Aug 2025 11:30:09 -0500
Subject: [PATCH] add web intelligent search
---
.../BotSharp.Core/BotSharp.Core.csproj | 9 +++
.../Conversations/ConversationPlugin.cs | 3 +
.../Demo/Functions/GetFunEventsFn.cs | 1 -
.../Functions/WebIntelligentSearchFn.cs | 68 +++++++++++++++++++
.../WebSearch/Hooks/WebSearchUtilityHook.cs | 22 ++++++
.../util-web-intelligent_search.json | 9 +++
.../util-web-intelligent_search.fn.liquid | 1 +
.../Functions/ReadImageFn.cs | 2 +-
8 files changed, 113 insertions(+), 2 deletions(-)
create mode 100644 src/Infrastructure/BotSharp.Core/WebSearch/Functions/WebIntelligentSearchFn.cs
create mode 100644 src/Infrastructure/BotSharp.Core/WebSearch/Hooks/WebSearchUtilityHook.cs
create mode 100644 src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-web-intelligent_search.json
create mode 100644 src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-web-intelligent_search.fn.liquid
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index 6833fdfc..7b0e55ac 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -99,6 +99,9 @@
+
+
+
@@ -215,6 +218,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
index 61c23d1b..64899ec4 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
@@ -16,6 +16,7 @@ using BotSharp.Core.Messaging;
using BotSharp.Core.Routing.Reasoning;
using BotSharp.Core.Templating;
using BotSharp.Core.Translation;
+using BotSharp.Core.WebSearch.Hooks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
@@ -67,6 +68,8 @@ public class ConversationPlugin : IBotSharpPlugin
services.AddScoped();
services.AddScoped();
services.AddScoped();
+
+ services.AddScoped();
}
public bool AttachMenu(List menu)
diff --git a/src/Infrastructure/BotSharp.Core/Demo/Functions/GetFunEventsFn.cs b/src/Infrastructure/BotSharp.Core/Demo/Functions/GetFunEventsFn.cs
index 87ddb1ee..818d4e5a 100644
--- a/src/Infrastructure/BotSharp.Core/Demo/Functions/GetFunEventsFn.cs
+++ b/src/Infrastructure/BotSharp.Core/Demo/Functions/GetFunEventsFn.cs
@@ -1,6 +1,5 @@
using BotSharp.Abstraction.Functions;
using BotSharp.Core.MessageHub;
-using System.Text.Json.Serialization;
namespace BotSharp.Core.Demo.Functions;
diff --git a/src/Infrastructure/BotSharp.Core/WebSearch/Functions/WebIntelligentSearchFn.cs b/src/Infrastructure/BotSharp.Core/WebSearch/Functions/WebIntelligentSearchFn.cs
new file mode 100644
index 00000000..138748fb
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/WebSearch/Functions/WebIntelligentSearchFn.cs
@@ -0,0 +1,68 @@
+using BotSharp.Abstraction.Functions;
+using BotSharp.Abstraction.MLTasks;
+
+namespace BotSharp.Core.WebSearch.Functions;
+
+public class WebIntelligentSearchFn : IFunctionCallback
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ public string Name => "util-web-intelligent_search";
+ public string Indication => "Searching web";
+
+ public WebIntelligentSearchFn(
+ IServiceProvider services,
+ ILogger logger)
+ {
+ _services = services;
+ _logger = logger;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var conv = _services.GetRequiredService();
+ var routingCtx = _services.GetRequiredService();
+ var agentService = _services.GetRequiredService();
+
+ Agent? fromAgent = null;
+ if (!string.IsNullOrEmpty(message.CurrentAgentId))
+ {
+ fromAgent = await agentService.GetAgent(message.CurrentAgentId);
+ }
+
+ var agent = new Agent
+ {
+ Id = fromAgent?.Id ?? BuiltInAgentId.UtilityAssistant,
+ Name = fromAgent?.Name ?? "AI Agent",
+ Instruction = "Please search the websites to handle user's request."
+ };
+
+ var dialogs = routingCtx.GetDialogs();
+ if (dialogs.IsNullOrEmpty())
+ {
+ dialogs = conv.GetDialogHistory();
+ }
+
+ var response = await GetChatCompletion(agent, dialogs);
+ message.Content = response;
+ return true;
+ }
+
+ private async Task GetChatCompletion(Agent agent, List dialogs)
+ {
+ try
+ {
+ var llmProviderService = _services.GetRequiredService();
+ var completion = CompletionProvider.GetChatCompletion(_services, provider: "openai", model: "gpt-4o-search-preview");
+ var response = await completion.GetChatCompletions(agent, dialogs);
+ return response.Content;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error when searching web.";
+ _logger.LogWarning(ex, $"{error}");
+ return error;
+ }
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/WebSearch/Hooks/WebSearchUtilityHook.cs b/src/Infrastructure/BotSharp.Core/WebSearch/Hooks/WebSearchUtilityHook.cs
new file mode 100644
index 00000000..0fcaf6d3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/WebSearch/Hooks/WebSearchUtilityHook.cs
@@ -0,0 +1,22 @@
+namespace BotSharp.Core.WebSearch.Hooks;
+
+public class WebSearchUtilityHook : IAgentUtilityHook
+{
+ private const string WEB_INTELLIGENT_SEARCH_FN = "util-web-intelligent_search";
+
+ public void AddUtilities(List utilities)
+ {
+ utilities.Add(new AgentUtility
+ {
+ Category = "web",
+ Name = "intelligent.search",
+ Items = [
+ new UtilityItem
+ {
+ FunctionName = WEB_INTELLIGENT_SEARCH_FN,
+ TemplateName = $"{WEB_INTELLIGENT_SEARCH_FN}.fn"
+ }
+ ]
+ });
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-web-intelligent_search.json b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-web-intelligent_search.json
new file mode 100644
index 00000000..bdad99fb
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-web-intelligent_search.json
@@ -0,0 +1,9 @@
+{
+ "name": "util-web-intelligent_search",
+ "description": "Search websites to handle user's request",
+ "parameters": {
+ "type": "object",
+ "properties": {},
+ "required": []
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-web-intelligent_search.fn.liquid b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-web-intelligent_search.fn.liquid
new file mode 100644
index 00000000..401a2e16
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-web-intelligent_search.fn.liquid
@@ -0,0 +1 @@
+Please call "util-web-intelligent_search" if user wants you to search content from websites.
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs
index 1a093797..f8a0f593 100644
--- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs
+++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs
@@ -28,7 +28,7 @@ public class ReadImageFn : IFunctionCallback
Agent? fromAgent = null;
if (!string.IsNullOrEmpty(message.CurrentAgentId))
{
- fromAgent = await agentService.LoadAgent(message.CurrentAgentId);
+ fromAgent = await agentService.GetAgent(message.CurrentAgentId);
}
var agent = new Agent