using System.ClientModel; using System.Diagnostics.CodeAnalysis; using System.Text.Json; using DysonNetwork.Insight.Thought.Plugins; using DysonNetwork.Shared.Models; using DysonNetwork.Shared.Proto; using DysonNetwork.Shared.Registry; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Connectors.Ollama; using Microsoft.SemanticKernel.Connectors.OpenAI; using OpenAI; using PostType = DysonNetwork.Shared.Proto.PostType; using Microsoft.SemanticKernel.Plugins.Web; using Microsoft.SemanticKernel.Plugins.Web.Bing; using Microsoft.SemanticKernel.Plugins.Web.Google; using NodaTime.Serialization.Protobuf; using NodaTime.Text; namespace DysonNetwork.Insight.Thought; public class ThoughtProvider { private readonly PostService.PostServiceClient _postClient; private readonly AccountService.AccountServiceClient _accountClient; private readonly IConfiguration _configuration; private readonly ILogger _logger; public Kernel Kernel { get; } private string? ModelProviderType { get; set; } public string? ModelDefault { get; set; } [Experimental("SKEXP0050")] public ThoughtProvider( IConfiguration configuration, PostService.PostServiceClient postServiceClient, AccountService.AccountServiceClient accountServiceClient, ILogger logger ) { _logger = logger; _postClient = postServiceClient; _accountClient = accountServiceClient; _configuration = configuration; Kernel = InitializeThinkingProvider(configuration); InitializeHelperFunctions(); } private Kernel InitializeThinkingProvider(IConfiguration configuration) { var cfg = configuration.GetSection("Thinking"); ModelProviderType = cfg.GetValue("Provider")?.ToLower(); ModelDefault = cfg.GetValue("Model"); var endpoint = cfg.GetValue("Endpoint"); var apiKey = cfg.GetValue("ApiKey"); var builder = Kernel.CreateBuilder(); switch (ModelProviderType) { case "ollama": builder.AddOllamaChatCompletion(ModelDefault!, new Uri(endpoint ?? "http://localhost:11434/api")); break; case "deepseek": var client = new OpenAIClient( new ApiKeyCredential(apiKey!), new OpenAIClientOptions { Endpoint = new Uri(endpoint ?? "https://api.deepseek.com/v1") } ); builder.AddOpenAIChatCompletion(ModelDefault!, client); break; default: throw new IndexOutOfRangeException("Unknown thinking provider: " + ModelProviderType); } return builder.Build(); } [Experimental("SKEXP0050")] private void InitializeHelperFunctions() { var accountPlugin = new SnAccountKernelPlugin(_accountClient); var postPlugin = new SnPostKernelPlugin(_postClient); // Add Solar Network tools plugin Kernel.ImportPluginFromFunctions("solar_network", [ KernelFunctionFactory.CreateFromMethod(accountPlugin.GetAccount), KernelFunctionFactory.CreateFromMethod(accountPlugin.GetAccountByName), KernelFunctionFactory.CreateFromMethod(postPlugin.GetPost), KernelFunctionFactory.CreateFromMethod(postPlugin.ListPosts), KernelFunctionFactory.CreateFromMethod(postPlugin.ListPostsWithinTime) ]); // Add web search plugins if configured var bingApiKey = _configuration.GetValue("Thinking:BingApiKey"); if (!string.IsNullOrEmpty(bingApiKey)) { var bingConnector = new BingConnector(bingApiKey); var bing = new WebSearchEnginePlugin(bingConnector); Kernel.ImportPluginFromObject(bing, "bing"); } var googleApiKey = _configuration.GetValue("Thinking:GoogleApiKey"); var googleCx = _configuration.GetValue("Thinking:GoogleCx"); if (!string.IsNullOrEmpty(googleApiKey) && !string.IsNullOrEmpty(googleCx)) { var googleConnector = new GoogleConnector( apiKey: googleApiKey, searchEngineId: googleCx); var google = new WebSearchEnginePlugin(googleConnector); Kernel.ImportPluginFromObject(google, "google"); } } public PromptExecutionSettings CreatePromptExecutionSettings() { switch (ModelProviderType) { case "ollama": return new OllamaPromptExecutionSettings { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false) }; case "deepseek": return new OpenAIPromptExecutionSettings { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false) }; default: throw new InvalidOperationException("Unknown provider: " + ModelProviderType); } } }