From 2e64b0ab3a10f5b454df149c1041c9fe3289affc Mon Sep 17 00:00:00 2001 From: Kasper Marstal Date: Thu, 21 Nov 2024 22:28:46 +0100 Subject: [PATCH 1/6] feat: Update Llamafile version, add larger Llamafile models --- src/Cellm/appsettings.Local.Anthropic.json | 2 +- src/Cellm/appsettings.Local.Llamafile.GPU.json | 4 +++- src/Cellm/appsettings.Local.Llamafile.json | 6 ++++-- src/Cellm/appsettings.Local.Mistral.json | 2 +- src/Cellm/appsettings.Local.OpenAi.json | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Cellm/appsettings.Local.Anthropic.json b/src/Cellm/appsettings.Local.Anthropic.json index 646b425..e8f2ea5 100644 --- a/src/Cellm/appsettings.Local.Anthropic.json +++ b/src/Cellm/appsettings.Local.Anthropic.json @@ -1,7 +1,7 @@ { "AnthropicConfiguration": { "DefaultModel": "claude-3-5-sonnet-20241022", - "ApiKey": "YOUR_ANTHROPIC_APIKEY" + "ApiKey": "YOUR_ANTHROPIC_API_KEY" }, "CellmConfiguration": { "DefaultProvider": "Anthropic", diff --git a/src/Cellm/appsettings.Local.Llamafile.GPU.json b/src/Cellm/appsettings.Local.Llamafile.GPU.json index c5e4de6..2c84d7a 100644 --- a/src/Cellm/appsettings.Local.Llamafile.GPU.json +++ b/src/Cellm/appsettings.Local.Llamafile.GPU.json @@ -5,8 +5,10 @@ "DefaultModel": "gemma-2-2b", "Models": { "gemma-2-2b": "https://huggingface.co/bartowski/gemma-2-2b-it-GGUF/resolve/main/gemma-2-2b-it-Q6_K.gguf", + "gemma-2-9b": "https://huggingface.co/bartowski/gemma-2-9b-it-GGUF/resolve/main/gemma-2-9b-it-Q4_K_L.gguf", "llama-3.2-1b": "https://huggingface.co/bartowski/Llama-3.2-1B-Instruct-GGUF/resolve/main/Llama-3.2-1B-Instruct-Q6_K_L.gguf", - "llama-3.2-3b": "https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_L.gguf" + "llama-3.2-3b": "https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_L.gguf", + "ministral-8b": "https://huggingface.co/bartowski/Ministral-8B-Instruct-2410-GGUF/resolve/main/Ministral-8B-Instruct-2410-Q5_K_L.gguf" }, "GPU": true, "GpuLayers": 999 diff --git a/src/Cellm/appsettings.Local.Llamafile.json b/src/Cellm/appsettings.Local.Llamafile.json index bb50b19..c6474fb 100644 --- a/src/Cellm/appsettings.Local.Llamafile.json +++ b/src/Cellm/appsettings.Local.Llamafile.json @@ -1,12 +1,14 @@ { "LlamafileConfiguration": { - "LlamafileUrl": "https://github.com/Mozilla-Ocho/llamafile/releases/download/0.8.13/llamafile-0.8.13", + "LlamafileUrl": "https://github.com/Mozilla-Ocho/llamafile/releases/download/0.8.16/llamafile-0.8.16", "BaseAddress": "http://127.0.0.1", "DefaultModel": "gemma-2-2b", "Models": { "gemma-2-2b": "https://huggingface.co/bartowski/gemma-2-2b-it-GGUF/resolve/main/gemma-2-2b-it-Q6_K.gguf", + "gemma-2-9b": "https://huggingface.co/bartowski/gemma-2-9b-it-GGUF/resolve/main/gemma-2-9b-it-Q4_K_L.gguf", "llama-3.2-1b": "https://huggingface.co/bartowski/Llama-3.2-1B-Instruct-GGUF/resolve/main/Llama-3.2-1B-Instruct-Q6_K_L.gguf", - "llama-3.2-3b": "https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_L.gguf" + "llama-3.2-3b": "https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_L.gguf", + "ministral-8b": "https://huggingface.co/bartowski/Ministral-8B-Instruct-2410-GGUF/resolve/main/Ministral-8B-Instruct-2410-Q5_K_L.gguf" } }, "CellmConfiguration": { diff --git a/src/Cellm/appsettings.Local.Mistral.json b/src/Cellm/appsettings.Local.Mistral.json index f00ceb0..4a64398 100644 --- a/src/Cellm/appsettings.Local.Mistral.json +++ b/src/Cellm/appsettings.Local.Mistral.json @@ -2,7 +2,7 @@ "OpenAiConfiguration": { "BaseAddress": "https://api.mistral.ai", "DefaultModel": "mistral-small-latest", - "ApiKey": "YOUR_MISTRAL_APIKEY" + "ApiKey": "YOUR_MISTRAL_API_KEY" }, "CellmConfiguration": { "DefaultProvider": "OpenAI", diff --git a/src/Cellm/appsettings.Local.OpenAi.json b/src/Cellm/appsettings.Local.OpenAi.json index 295db65..de345fc 100644 --- a/src/Cellm/appsettings.Local.OpenAi.json +++ b/src/Cellm/appsettings.Local.OpenAi.json @@ -1,7 +1,7 @@ { "OpenAiConfiguration": { "DefaultModel": "gpt-4o-mini", - "ApiKey": "YOUR_OPENAI_APIKEY" + "ApiKey": "YOUR_OPENAI_API_KEY" }, "CellmConfiguration": { "DefaultProvider": "OpenAI", From 79728ddba07265792903f558c44513b302495e6d Mon Sep 17 00:00:00 2001 From: Kasper Marstal Date: Thu, 21 Nov 2024 22:37:13 +0100 Subject: [PATCH 2/6] refactor: Clean up Cellm/AddIn --- .../AddIn/{Functions.cs => CellmFunctions.cs} | 27 ++++----------- ...umentParser.cs => PromptArgumentParser.cs} | 33 ++++++++++--------- .../{AddIn => Prompts}/SystemMessages.cs | 2 +- src/Cellm/Services/ServiceLocator.cs | 3 +- 4 files changed, 27 insertions(+), 38 deletions(-) rename src/Cellm/AddIn/{Functions.cs => CellmFunctions.cs} (90%) rename src/Cellm/AddIn/{PromptWithArgumentParser.cs => PromptArgumentParser.cs} (82%) rename src/Cellm/{AddIn => Prompts}/SystemMessages.cs (94%) diff --git a/src/Cellm/AddIn/Functions.cs b/src/Cellm/AddIn/CellmFunctions.cs similarity index 90% rename from src/Cellm/AddIn/Functions.cs rename to src/Cellm/AddIn/CellmFunctions.cs index 30e2dd3..ab995ae 100644 --- a/src/Cellm/AddIn/Functions.cs +++ b/src/Cellm/AddIn/CellmFunctions.cs @@ -10,7 +10,7 @@ namespace Cellm.AddIn; -public static class Functions +public static class CellmFunctions { /// /// Sends a prompt to the default model configured in CellmConfiguration. @@ -73,7 +73,7 @@ public static object PromptWith( { try { - var arguments = ServiceLocator.Get() + var arguments = ServiceLocator.Get() .AddProvider(providerAndModel) .AddModel(providerAndModel) .AddInstructionsOrContext(instructionsOrContext) @@ -88,8 +88,8 @@ public static object PromptWith( var prompt = new PromptBuilder() .SetModel(arguments.Model) - .SetSystemMessage(SystemMessages.SystemMessage) .SetTemperature(arguments.Temperature) + .AddSystemMessage(SystemMessages.SystemMessage) .AddUserMessage(userMessage) .Build(); @@ -102,6 +102,7 @@ public static object PromptWith( catch (CellmException ex) { SentrySdk.CaptureException(ex); + Debug.WriteLine(ex); return ex.Message; } } @@ -117,22 +118,8 @@ public static object PromptWith( private static async Task CallModelAsync(Prompt prompt, string? provider = null, Uri? baseAddress = null) { - try - { - var client = ServiceLocator.Get(); - var response = await client.Send(prompt, provider, baseAddress); - var content = response.Messages.Last().Content; - return content; - } - catch (CellmException ex) - { - Debug.WriteLine(ex); - throw; - } - catch (Exception ex) - { - Debug.WriteLine(ex); - throw new CellmException("An unexpected error occurred", ex); - } + var client = ServiceLocator.Get(); + var response = await client.Send(prompt, provider, baseAddress); + return response.Messages.Last().Text ?? throw new NullReferenceException("No text response"); } } diff --git a/src/Cellm/AddIn/PromptWithArgumentParser.cs b/src/Cellm/AddIn/PromptArgumentParser.cs similarity index 82% rename from src/Cellm/AddIn/PromptWithArgumentParser.cs rename to src/Cellm/AddIn/PromptArgumentParser.cs index 3303fe6..80ca04d 100644 --- a/src/Cellm/AddIn/PromptWithArgumentParser.cs +++ b/src/Cellm/AddIn/PromptArgumentParser.cs @@ -1,5 +1,6 @@ using System.Text; using Cellm.AddIn.Exceptions; +using Cellm.Prompts; using ExcelDna.Integration; using Microsoft.Extensions.Configuration; using Microsoft.Office.Interop.Excel; @@ -8,7 +9,7 @@ namespace Cellm.AddIn; public record Arguments(string Provider, string Model, string Context, string Instructions, double Temperature); -public class PromptWithArgumentParser +public class PromptArgumentParser { private string? _provider; private string? _model; @@ -18,12 +19,12 @@ public class PromptWithArgumentParser private readonly IConfiguration _configuration; - public PromptWithArgumentParser(IConfiguration configuration) + public PromptArgumentParser(IConfiguration configuration) { _configuration = configuration; } - public PromptWithArgumentParser AddProvider(object providerAndModel) + public PromptArgumentParser AddProvider(object providerAndModel) { _provider = providerAndModel switch { @@ -35,7 +36,7 @@ public PromptWithArgumentParser AddProvider(object providerAndModel) return this; } - public PromptWithArgumentParser AddModel(object providerAndModel) + public PromptArgumentParser AddModel(object providerAndModel) { _model = providerAndModel switch { @@ -47,21 +48,21 @@ public PromptWithArgumentParser AddModel(object providerAndModel) return this; } - public PromptWithArgumentParser AddInstructionsOrContext(object instructionsOrContext) + public PromptArgumentParser AddInstructionsOrContext(object instructionsOrContext) { _instructionsOrContext = instructionsOrContext; return this; } - public PromptWithArgumentParser AddInstructionsOrTemperature(object instructionsOrTemperature) + public PromptArgumentParser AddInstructionsOrTemperature(object instructionsOrTemperature) { _instructionsOrTemperature = instructionsOrTemperature; return this; } - public PromptWithArgumentParser AddTemperature(object temperature) + public PromptArgumentParser AddTemperature(object temperature) { _temperature = temperature; @@ -92,17 +93,17 @@ public Arguments Parse() // "=PROMPT("Extract keywords", 0.7) (string instructions, double temperature, ExcelMissing) => new Arguments(provider, model, string.Empty, RenderInstructions(instructions), ParseTemperature(temperature)), // "=PROMPT(A1:B2) - (ExcelReference context, ExcelMissing, ExcelMissing) => new Arguments(provider, model, RenderContext(ParseCells(context)), RenderInstructions(SystemMessages.InlineInstructions), ParseTemperature(defaultTemperature)), + (ExcelReference context, ExcelMissing, ExcelMissing) => new Arguments(provider, model, RenderCells(ParseCells(context)), RenderInstructions(SystemMessages.InlineInstructions), ParseTemperature(defaultTemperature)), // "=PROMPT(A1:B2, 0.7) - (ExcelReference context, double temperature, ExcelMissing) => new Arguments(provider, model, RenderContext(ParseCells(context)), RenderInstructions(SystemMessages.InlineInstructions), ParseTemperature(defaultTemperature)), + (ExcelReference context, double temperature, ExcelMissing) => new Arguments(provider, model, RenderCells(ParseCells(context)), RenderInstructions(SystemMessages.InlineInstructions), ParseTemperature(defaultTemperature)), // "=PROMPT(A1:B2, "Extract keywords") - (ExcelReference context, string instructions, ExcelMissing) => new Arguments(provider, model, RenderContext(ParseCells(context)), RenderInstructions(instructions), ParseTemperature(defaultTemperature)), + (ExcelReference context, string instructions, ExcelMissing) => new Arguments(provider, model, RenderCells(ParseCells(context)), RenderInstructions(instructions), ParseTemperature(defaultTemperature)), // "=PROMPT(A1:B2, "Extract keywords", 0.7) - (ExcelReference context, string instructions, double temperature) => new Arguments(provider, model, RenderContext(ParseCells(context)), RenderInstructions(instructions), ParseTemperature(temperature)), + (ExcelReference context, string instructions, double temperature) => new Arguments(provider, model, RenderCells(ParseCells(context)), RenderInstructions(instructions), ParseTemperature(temperature)), // "=PROMPT(A1:B2, C1:D2) - (ExcelReference context, ExcelReference instructions, ExcelMissing) => new Arguments(provider, model, RenderContext(ParseCells(context)), RenderInstructions(ParseCells(instructions)), ParseTemperature(defaultTemperature)), + (ExcelReference context, ExcelReference instructions, ExcelMissing) => new Arguments(provider, model, RenderCells(ParseCells(context)), RenderInstructions(ParseCells(instructions)), ParseTemperature(defaultTemperature)), // "=PROMPT(A1:B2, C1:D2, 0.7) - (ExcelReference context, ExcelReference instructions, double temperature) => new Arguments(provider, model, RenderContext(ParseCells(context)), RenderInstructions(ParseCells(instructions)), ParseTemperature(temperature)), + (ExcelReference context, ExcelReference instructions, double temperature) => new Arguments(provider, model, RenderCells(ParseCells(context)), RenderInstructions(ParseCells(instructions)), ParseTemperature(temperature)), // Anything else _ => throw new ArgumentException($"Invalid arguments ({_instructionsOrContext?.GetType().Name}, {_instructionsOrTemperature?.GetType().Name}, {_temperature?.GetType().Name})") }; @@ -110,7 +111,7 @@ public Arguments Parse() private static string GetProvider(string providerAndModel) { - var index = providerAndModel.IndexOf("/"); + var index = providerAndModel.IndexOf('/'); if (index < 0) { @@ -122,7 +123,7 @@ private static string GetProvider(string providerAndModel) private static string GetModel(string providerAndModel) { - var index = providerAndModel.IndexOf("/"); + var index = providerAndModel.IndexOf('/'); if (index < 0) { @@ -203,7 +204,7 @@ private static string GetRowName(int rowNumber) return (rowNumber + 1).ToString(); } - private static string RenderContext(string context) + private static string RenderCells(string context) { return new StringBuilder() .AppendLine("") diff --git a/src/Cellm/AddIn/SystemMessages.cs b/src/Cellm/Prompts/SystemMessages.cs similarity index 94% rename from src/Cellm/AddIn/SystemMessages.cs rename to src/Cellm/Prompts/SystemMessages.cs index 971fbb3..bedcad4 100644 --- a/src/Cellm/AddIn/SystemMessages.cs +++ b/src/Cellm/Prompts/SystemMessages.cs @@ -1,4 +1,4 @@ -namespace Cellm.AddIn; +namespace Cellm.Prompts; internal static class SystemMessages { diff --git a/src/Cellm/Services/ServiceLocator.cs b/src/Cellm/Services/ServiceLocator.cs index c54a52e..bb47490 100644 --- a/src/Cellm/Services/ServiceLocator.cs +++ b/src/Cellm/Services/ServiceLocator.cs @@ -87,12 +87,13 @@ private static IServiceCollection ConfigureServices(IServiceCollection services) .AddSingleton(configuration) .AddMemoryCache() .AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())) - .AddTransient() + .AddTransient() .AddSingleton() .AddSingleton(); // Tools services + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() From 0b0f5af3909587d87b82160661aa3ce8be3fa6c8 Mon Sep 17 00:00:00 2001 From: Kasper Marstal Date: Thu, 21 Nov 2024 22:45:35 +0100 Subject: [PATCH 3/6] fix: Build errors --- src/Cellm/AddIn/CellmFunctions.cs | 2 +- src/Cellm/Services/ServiceLocator.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Cellm/AddIn/CellmFunctions.cs b/src/Cellm/AddIn/CellmFunctions.cs index ab995ae..648cfcf 100644 --- a/src/Cellm/AddIn/CellmFunctions.cs +++ b/src/Cellm/AddIn/CellmFunctions.cs @@ -120,6 +120,6 @@ private static async Task CallModelAsync(Prompt prompt, string? provider { var client = ServiceLocator.Get(); var response = await client.Send(prompt, provider, baseAddress); - return response.Messages.Last().Text ?? throw new NullReferenceException("No text response"); + return response.Messages.Last().Content; } } diff --git a/src/Cellm/Services/ServiceLocator.cs b/src/Cellm/Services/ServiceLocator.cs index bb47490..9ee296a 100644 --- a/src/Cellm/Services/ServiceLocator.cs +++ b/src/Cellm/Services/ServiceLocator.cs @@ -93,7 +93,6 @@ private static IServiceCollection ConfigureServices(IServiceCollection services) // Tools services - .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() From 618ad8ff45d5cad6c72722d1c89b633173e16f31 Mon Sep 17 00:00:00 2001 From: Kasper Marstal Date: Thu, 21 Nov 2024 23:01:20 +0100 Subject: [PATCH 4/6] feat: Use Microsft.Extensions.AI --- src/Cellm/AddIn/CellmConfiguration.cs | 2 + src/Cellm/AddIn/CellmFunctions.cs | 2 +- src/Cellm/Cellm.csproj | 5 + .../Anthropic/AnthropicRequestHandler.cs | 9 +- src/Cellm/Models/IModelRequestHandler.cs | 3 - .../ModelRequestBehavior/CachingBehavior.cs | 2 +- .../ModelRequestBehavior/SentryBehavior.cs | 2 +- .../ModelRequestBehavior/ToolBehavior.cs | 45 ++--- src/Cellm/Models/OpenAi/Extensions.cs | 50 ----- src/Cellm/Models/OpenAi/Models.cs | 53 ----- .../Models/OpenAi/OpenAiConfiguration.cs | 3 - .../Models/OpenAi/OpenAiRequestHandler.cs | 102 +++------- src/Cellm/Prompts/Message.cs | 3 - src/Cellm/Prompts/Prompt.cs | 6 +- src/Cellm/Prompts/PromptBuilder.cs | 64 ++---- src/Cellm/Prompts/Roles.cs | 9 - src/Cellm/Prompts/Tool.cs | 5 - src/Cellm/Prompts/ToolCall.cs | 3 - src/Cellm/Services/ServiceLocator.cs | 4 +- .../Tools/FileReader/FileReaderFactory.cs | 2 +- .../Tools/FileReader/FileReaderRequest.cs | 4 +- .../FileReader/FileReaderRequestHandler.cs | 13 +- .../Tools/FileReader/FileReaderResponse.cs | 4 +- src/Cellm/Tools/FileReader/IFileReader.cs | 2 +- src/Cellm/Tools/FileReader/PdfReader.cs | 2 +- src/Cellm/Tools/FileReader/TextReader.cs | 4 +- src/Cellm/Tools/Functions.cs | 33 ++++ src/Cellm/Tools/Glob/GlobRequest.cs | 9 +- src/Cellm/Tools/Glob/GlobRequestHandler.cs | 2 +- src/Cellm/Tools/Glob/GlobResponse.cs | 7 +- src/Cellm/Tools/ITool.cs | 5 - src/Cellm/Tools/ToolFactory.cs | 92 --------- src/Cellm/Tools/ToolRunner.cs | 49 ----- src/Cellm/appsettings.json | 3 +- src/Cellm/packages.lock.json | 187 +++++++++--------- 35 files changed, 226 insertions(+), 564 deletions(-) delete mode 100644 src/Cellm/Models/OpenAi/Extensions.cs delete mode 100644 src/Cellm/Models/OpenAi/Models.cs delete mode 100644 src/Cellm/Prompts/Message.cs delete mode 100644 src/Cellm/Prompts/Roles.cs delete mode 100644 src/Cellm/Prompts/Tool.cs delete mode 100644 src/Cellm/Prompts/ToolCall.cs create mode 100644 src/Cellm/Tools/Functions.cs delete mode 100644 src/Cellm/Tools/ITool.cs delete mode 100644 src/Cellm/Tools/ToolFactory.cs delete mode 100644 src/Cellm/Tools/ToolRunner.cs diff --git a/src/Cellm/AddIn/CellmConfiguration.cs b/src/Cellm/AddIn/CellmConfiguration.cs index 4685063..54a136a 100644 --- a/src/Cellm/AddIn/CellmConfiguration.cs +++ b/src/Cellm/AddIn/CellmConfiguration.cs @@ -15,5 +15,7 @@ public class CellmConfiguration public int HttpTimeoutInSeconds { get; init; } public int CacheTimeoutInSeconds { get; init; } + + public bool EnableTools { get; init; } } diff --git a/src/Cellm/AddIn/CellmFunctions.cs b/src/Cellm/AddIn/CellmFunctions.cs index 648cfcf..ab995ae 100644 --- a/src/Cellm/AddIn/CellmFunctions.cs +++ b/src/Cellm/AddIn/CellmFunctions.cs @@ -120,6 +120,6 @@ private static async Task CallModelAsync(Prompt prompt, string? provider { var client = ServiceLocator.Get(); var response = await client.Send(prompt, provider, baseAddress); - return response.Messages.Last().Content; + return response.Messages.Last().Text ?? throw new NullReferenceException("No text response"); } } diff --git a/src/Cellm/Cellm.csproj b/src/Cellm/Cellm.csproj index 126a441..5c0642e 100644 --- a/src/Cellm/Cellm.csproj +++ b/src/Cellm/Cellm.csproj @@ -23,6 +23,11 @@ + + + + + diff --git a/src/Cellm/Models/Anthropic/AnthropicRequestHandler.cs b/src/Cellm/Models/Anthropic/AnthropicRequestHandler.cs index b1e6d56..378057d 100644 --- a/src/Cellm/Models/Anthropic/AnthropicRequestHandler.cs +++ b/src/Cellm/Models/Anthropic/AnthropicRequestHandler.cs @@ -6,6 +6,7 @@ using Cellm.AddIn.Exceptions; using Cellm.Models.Anthropic.Models; using Cellm.Prompts; +using Microsoft.Extensions.AI; using Microsoft.Extensions.Options; namespace Cellm.Models.Anthropic; @@ -52,11 +53,11 @@ public string Serialize(AnthropicRequest request) { var requestBody = new AnthropicRequestBody { - System = request.Prompt.SystemMessage, - Messages = request.Prompt.Messages.Select(x => new AnthropicMessage { Content = x.Content, Role = x.Role.ToString().ToLower() }).ToList(), - Model = request.Prompt.Model ?? _anthropicConfiguration.DefaultModel, + System = request.Prompt.Messages.Where(x => x.Role == ChatRole.System).First().Text, + Messages = request.Prompt.Messages.Select(x => new AnthropicMessage { Content = x.Text, Role = x.Role.ToString().ToLower() }).ToList(), + Model = request.Prompt.Options.ModelId ?? _anthropicConfiguration.DefaultModel, MaxTokens = _cellmConfiguration.MaxOutputTokens, - Temperature = request.Prompt.Temperature + Temperature = request.Prompt.Options.Temperature ?? _cellmConfiguration.DefaultTemperature, }; return _serde.Serialize(requestBody, new JsonSerializerOptions diff --git a/src/Cellm/Models/IModelRequestHandler.cs b/src/Cellm/Models/IModelRequestHandler.cs index d4983a6..dcb67e5 100644 --- a/src/Cellm/Models/IModelRequestHandler.cs +++ b/src/Cellm/Models/IModelRequestHandler.cs @@ -5,7 +5,4 @@ namespace Cellm.Models; internal interface IModelRequestHandler : IRequestHandler where TRequest : IRequest { - public string Serialize(TRequest request); - - public TResponse Deserialize(TRequest request, string response); } diff --git a/src/Cellm/Models/ModelRequestBehavior/CachingBehavior.cs b/src/Cellm/Models/ModelRequestBehavior/CachingBehavior.cs index 0f35565..9e96b2f 100644 --- a/src/Cellm/Models/ModelRequestBehavior/CachingBehavior.cs +++ b/src/Cellm/Models/ModelRequestBehavior/CachingBehavior.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; -namespace Cellm.Models.PipelineBehavior; +namespace Cellm.Models.ModelRequestBehavior; internal class CachingBehavior : IPipelineBehavior where TRequest : IModelRequest diff --git a/src/Cellm/Models/ModelRequestBehavior/SentryBehavior.cs b/src/Cellm/Models/ModelRequestBehavior/SentryBehavior.cs index e4d93b4..5ee3915 100644 --- a/src/Cellm/Models/ModelRequestBehavior/SentryBehavior.cs +++ b/src/Cellm/Models/ModelRequestBehavior/SentryBehavior.cs @@ -1,6 +1,6 @@ using MediatR; -namespace Cellm.Models.PipelineBehavior; +namespace Cellm.Models.ModelRequestBehavior; internal class SentryBehavior : IPipelineBehavior where TRequest : notnull diff --git a/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs b/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs index 36c4df9..fbdf857 100644 --- a/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs +++ b/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs @@ -1,46 +1,37 @@ -using Cellm.Prompts; +using Cellm.AddIn; using Cellm.Tools; using MediatR; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Options; -namespace Cellm.Models.PipelineBehavior; +namespace Cellm.Models.ModelRequestBehavior; internal class ToolBehavior : IPipelineBehavior where TRequest : IModelRequest - where TResponse : IModelResponse { - private readonly ISender _sender; - private readonly ToolRunner _toolRunner; + private readonly CellmConfiguration _cellmConfiguration; + private readonly Functions _functions; + private readonly List _tools; - public ToolBehavior(ISender sender, ToolRunner toolRunner) + public ToolBehavior(IOptions cellmConfiguration, Functions functions) { - _sender = sender; - _toolRunner = toolRunner; + _cellmConfiguration = cellmConfiguration.Value; + _functions = functions; + _tools = [ + AIFunctionFactory.Create(_functions.GlobRequest), + AIFunctionFactory.Create(_functions.FileReaderRequest) + ]; } public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) { - var response = await next(); - - var toolCalls = response.Prompt.Messages.LastOrDefault()?.ToolCalls; - - if (toolCalls is not null) + if (_cellmConfiguration.EnableTools) { - // Model called tools, run tools and call model again - var message = await RunTools(toolCalls); - request.Prompt.Messages.Add(message); - response = await _sender.Send(request, cancellationToken); + request.Prompt.Options.Tools = _tools; } + + var response = await next(); return response; } - - private async Task RunTools(List toolCalls) - { - var toolResults = await Task.WhenAll(toolCalls.Select(x => _toolRunner.Run(x))); - var toolCallsWithResults = toolCalls - .Zip(toolResults, (toolCall, toolResult) => toolCall with { Result = toolResult }) - .ToList(); - - return new Message(string.Empty, Roles.Tool, toolCallsWithResults); - } } diff --git a/src/Cellm/Models/OpenAi/Extensions.cs b/src/Cellm/Models/OpenAi/Extensions.cs deleted file mode 100644 index 352e780..0000000 --- a/src/Cellm/Models/OpenAi/Extensions.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Cellm.AddIn.Exceptions; -using Cellm.Models.OpenAi.Models; -using Cellm.Prompts; -using Cellm.Tools; - -namespace Cellm.Models.OpenAi; - -internal static class Extensions -{ - public static List ToOpenAiMessages(this Prompt prompt) - { - return prompt.Messages.SelectMany(x => ToOpenAiMessage(x)).ToList(); - } - - private static List ToOpenAiMessage(Message message) - { - return message.Role switch - { - Roles.Tool => ToOpenAiToolResults(message), - _ => new List() - { - new OpenAiMessage( - message.Role.ToString().ToLower(), - message.Content, - message.ToolCalls? - .Select(x => new OpenAiToolCall(x.Id, "function", new OpenAiFunctionCall(x.Name, x.Arguments))) - .ToList()) - } - }; - } - - private static List ToOpenAiToolResults(Message message) - { - var toolCalls = message?.ToolCalls ?? throw new CellmException("No tool calls in tool message"); - return toolCalls - .Select(x => new OpenAiMessage( - Roles.Tool.ToString().ToLower(), - $"Tool: {x.Name}, Arguments: {x.Arguments}, Result: {x.Result}", - null, - x.Id) - ).ToList(); - } - - public static List ToOpenAiTools(this ToolRunner toolRunner) - { - return toolRunner.GetTools() - .Select(x => new OpenAiTool("function", new OpenAiFunction(x.Name, x.Description, x.Parameters))) - .ToList(); - } -} diff --git a/src/Cellm/Models/OpenAi/Models.cs b/src/Cellm/Models/OpenAi/Models.cs deleted file mode 100644 index fef02a8..0000000 --- a/src/Cellm/Models/OpenAi/Models.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Text.Json; - -namespace Cellm.Models.OpenAi.Models; - -public record OpenAiChatCompletionRequest( - string Model, - List Messages, - int MaxTokens, - double Temperature, - List? Tools = null, - string? ToolChoice = null); - -public record OpenAiChatCompletionResponse( - string Id, - string Object, - long Created, - string Model, - List Choices, - OpenAiUsage? Usage = null); - -public record OpenAiMessage( - string Role, - string Content, - List? ToolCalls = null, - string? ToolCallId = null); - -public record OpenAiTool( - string Type, - OpenAiFunction Function); - -public record OpenAiFunction( - string Name, - string Description, - JsonDocument Parameters); - -public record OpenAiChoice( - int Index, - OpenAiMessage Message, - string FinishReason); - -public record OpenAiToolCall( - string Id, - string Type, - OpenAiFunctionCall Function); - -public record OpenAiFunctionCall( - string Name, - string Arguments); - -public record OpenAiUsage( - int PromptTokens, - int CompletionTokens, - int TotalTokens); diff --git a/src/Cellm/Models/OpenAi/OpenAiConfiguration.cs b/src/Cellm/Models/OpenAi/OpenAiConfiguration.cs index 5b04f6d..3569856 100644 --- a/src/Cellm/Models/OpenAi/OpenAiConfiguration.cs +++ b/src/Cellm/Models/OpenAi/OpenAiConfiguration.cs @@ -10,13 +10,10 @@ internal class OpenAiConfiguration : IProviderConfiguration public string ApiKey { get; init; } - public bool EnableTools { get; init; } - public OpenAiConfiguration() { BaseAddress = default!; DefaultModel = default!; ApiKey = default!; - EnableTools = default; } } diff --git a/src/Cellm/Models/OpenAi/OpenAiRequestHandler.cs b/src/Cellm/Models/OpenAi/OpenAiRequestHandler.cs index e1538a2..8016470 100644 --- a/src/Cellm/Models/OpenAi/OpenAiRequestHandler.cs +++ b/src/Cellm/Models/OpenAi/OpenAiRequestHandler.cs @@ -1,100 +1,48 @@ -using System.Text; -using System.Text.Encodings.Web; -using System.Text.Json; -using System.Text.Json.Serialization; -using Cellm.AddIn; -using Cellm.AddIn.Exceptions; -using Cellm.Models.OpenAi.Models; +using System.ClientModel; +using System.ClientModel.Primitives; using Cellm.Prompts; -using Cellm.Tools; +using Microsoft.Extensions.AI; using Microsoft.Extensions.Options; +using OpenAI; namespace Cellm.Models.OpenAi; -internal class OpenAiRequestHandler : IModelRequestHandler +internal class OpenAiRequestHandler(IOptions openAiConfiguration, HttpClient httpClient) : IModelRequestHandler { - private readonly OpenAiConfiguration _openAiConfiguration; - private readonly CellmConfiguration _cellmConfiguration; - private readonly HttpClient _httpClient; - private readonly ToolRunner _toolRunner; - private readonly Serde _serde; - - public OpenAiRequestHandler( - IOptions openAiConfiguration, - IOptions cellmConfiguration, - HttpClient httpClient, - ToolRunner toolRunner, - Serde serde) - { - _openAiConfiguration = openAiConfiguration.Value; - _cellmConfiguration = cellmConfiguration.Value; - _httpClient = httpClient; - _toolRunner = toolRunner; - _serde = serde; - } + private readonly OpenAiConfiguration _openAiConfiguration = openAiConfiguration.Value; public async Task Handle(OpenAiRequest request, CancellationToken cancellationToken) { + var modelId = request.Prompt.Options.ModelId ?? _openAiConfiguration.DefaultModel; + const string path = "/v1/chat/completions"; var address = request.BaseAddress is null ? new Uri(path, UriKind.Relative) : new Uri(request.BaseAddress, path); - var json = Serialize(request); - var jsonAsStringContent = new StringContent(json, Encoding.UTF8, "application/json"); - - var response = await _httpClient.PostAsync(address, jsonAsStringContent, cancellationToken); - var responseBodyAsString = await response.Content.ReadAsStringAsync(cancellationToken); + // Must instantiate manually because address can be set/changed only at instantiation + var chatClient = GetChatClient(address, modelId); + var chatCompletion = await chatClient.CompleteAsync(request.Prompt.Messages, request.Prompt.Options, cancellationToken); - if (!response.IsSuccessStatusCode) - { - throw new HttpRequestException($"{nameof(OpenAiRequest)} failed: {responseBodyAsString}", null, response.StatusCode); - } - - return Deserialize(request, responseBodyAsString); - } - - public string Serialize(OpenAiRequest request) - { - var openAiPrompt = new PromptBuilder(request.Prompt) - .AddSystemMessage() + var prompt = new PromptBuilder(request.Prompt) + .AddMessage(chatCompletion.Message) .Build(); - var chatCompletionRequest = new OpenAiChatCompletionRequest( - openAiPrompt.Model, - openAiPrompt.ToOpenAiMessages(), - _cellmConfiguration.MaxOutputTokens, - openAiPrompt.Temperature, - _toolRunner.ToOpenAiTools(), - "auto"); - - return _serde.Serialize(chatCompletionRequest, new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }); + return new OpenAiResponse(prompt); } - public OpenAiResponse Deserialize(OpenAiRequest request, string responseBodyAsString) + private IChatClient GetChatClient(Uri address, string modelId) { - var responseBody = _serde.Deserialize(responseBodyAsString, new JsonSerializerOptions + var openAiClientCredentials = new ApiKeyCredential(_openAiConfiguration.ApiKey); + var openAiClientOptions = new OpenAIClientOptions { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }); - - var choice = responseBody?.Choices?.FirstOrDefault() ?? throw new CellmException("Empty response from OpenAI API"); - var toolCalls = choice.Message.ToolCalls? - .Select(x => new ToolCall(x.Id, x.Function.Name, x.Function.Arguments, null)) - .ToList(); + Transport = new HttpClientPipelineTransport(httpClient), + Endpoint = address + }; - var content = choice.Message.Content; - var message = new Message(content, Roles.Assistant, toolCalls); + var openAiClient = new OpenAIClient(openAiClientCredentials, openAiClientOptions); - var prompt = new PromptBuilder(request.Prompt) - .AddMessage(message) - .Build(); - - return new OpenAiResponse(prompt); + return new ChatClientBuilder() + .UseLogging() + .UseFunctionInvocation() + .Use(openAiClient.AsChatClient(modelId)); } } diff --git a/src/Cellm/Prompts/Message.cs b/src/Cellm/Prompts/Message.cs deleted file mode 100644 index 3870e1b..0000000 --- a/src/Cellm/Prompts/Message.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Cellm.Prompts; - -public record Message(string Content, Roles Role, List? ToolCalls = null); \ No newline at end of file diff --git a/src/Cellm/Prompts/Prompt.cs b/src/Cellm/Prompts/Prompt.cs index 9868746..6c12052 100644 --- a/src/Cellm/Prompts/Prompt.cs +++ b/src/Cellm/Prompts/Prompt.cs @@ -1,3 +1,5 @@ -namespace Cellm.Prompts; +using Microsoft.Extensions.AI; -public record Prompt(string Model, string SystemMessage, List Messages, double Temperature, List Tools); +namespace Cellm.Prompts; + +public record Prompt(IList Messages, ChatOptions Options); diff --git a/src/Cellm/Prompts/PromptBuilder.cs b/src/Cellm/Prompts/PromptBuilder.cs index b676a05..77a6ebc 100644 --- a/src/Cellm/Prompts/PromptBuilder.cs +++ b/src/Cellm/Prompts/PromptBuilder.cs @@ -1,14 +1,13 @@ using Cellm.AddIn.Exceptions; +using Microsoft.Extensions.AI; namespace Cellm.Prompts; public class PromptBuilder { - private string? _model; - private string? _systemMessage; - private List _messages = new(); - private double? _temperature; - private List _tools = new(); + private List _messages = new(); + private ChatOptions _options = new(); + private List _tools = new(); public PromptBuilder() { @@ -16,84 +15,61 @@ public PromptBuilder() public PromptBuilder(Prompt prompt) { - _model = prompt.Model; - _systemMessage = prompt.SystemMessage; - _messages = prompt.Messages; - _temperature = prompt.Temperature; + // Do not mutate prompt + _messages = new List(prompt.Messages); + _options = prompt.Options.Clone(); } public PromptBuilder SetModel(string model) { - _model = model; - return this; - } - - public PromptBuilder SetSystemMessage(string systemMessage) - { - _systemMessage = systemMessage; + _options.ModelId = model; return this; } public PromptBuilder SetTemperature(double temperature) { - _temperature = temperature; - return this; - } - - public PromptBuilder AddSystemMessage() - { - if (string.IsNullOrEmpty(_systemMessage)) - { - throw new CellmException("Cannot add empty system message"); - } - - _messages.Insert(0, new Message(_systemMessage!, Roles.System)); + _options.Temperature = (float)temperature; return this; } public PromptBuilder AddSystemMessage(string content) { - _messages.Add(new Message(content, Roles.System)); + _messages.Add(new ChatMessage(ChatRole.System, content)); return this; } public PromptBuilder AddUserMessage(string content) { - _messages.Add(new Message(content, Roles.User)); + _messages.Add(new ChatMessage(ChatRole.User, content)); return this; } - public PromptBuilder AddAssistantMessage(string content, List? toolCalls = null) + public PromptBuilder AddAssistantMessage(string content) { - _messages.Add(new Message(content, Roles.Assistant, toolCalls)); + _messages.Add(new ChatMessage(ChatRole.User, content)); return this; } - public PromptBuilder AddMessage(Message message) + public PromptBuilder AddMessage(ChatMessage message) { - return AddMessages(new List { message }); + _messages.Add(message); + return this; } - public PromptBuilder AddMessages(List messages) + public PromptBuilder AddMessages(List messages) { _messages.AddRange(messages); return this; } - public PromptBuilder AddTools(List tools) + public PromptBuilder SetTools(IList tools) { - _tools = tools; + _options.Tools = tools; return this; } public Prompt Build() { - return new Prompt( - _model ?? throw new ArgumentNullException(nameof(_model)), - _systemMessage ?? string.Empty, - _messages, - _temperature ?? throw new ArgumentNullException(nameof(_temperature)), - _tools - ); + return new Prompt(_messages, _options); } } diff --git a/src/Cellm/Prompts/Roles.cs b/src/Cellm/Prompts/Roles.cs deleted file mode 100644 index 9746734..0000000 --- a/src/Cellm/Prompts/Roles.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Cellm.Prompts; - -public enum Roles -{ - System, - User, - Assistant, - Tool -} diff --git a/src/Cellm/Prompts/Tool.cs b/src/Cellm/Prompts/Tool.cs deleted file mode 100644 index 04446ea..0000000 --- a/src/Cellm/Prompts/Tool.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Text.Json; - -namespace Cellm.Prompts; - -public record Tool(string Name, string Description, JsonDocument Parameters); diff --git a/src/Cellm/Prompts/ToolCall.cs b/src/Cellm/Prompts/ToolCall.cs deleted file mode 100644 index c0ed06a..0000000 --- a/src/Cellm/Prompts/ToolCall.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Cellm.Prompts; - -public record ToolCall(string Id, string Name, string Arguments, string? Result); \ No newline at end of file diff --git a/src/Cellm/Services/ServiceLocator.cs b/src/Cellm/Services/ServiceLocator.cs index 9ee296a..9b06208 100644 --- a/src/Cellm/Services/ServiceLocator.cs +++ b/src/Cellm/Services/ServiceLocator.cs @@ -5,7 +5,7 @@ using Cellm.Models.Anthropic; using Cellm.Models.Llamafile; using Cellm.Models.OpenAi; -using Cellm.Models.PipelineBehavior; +using Cellm.Models.ModelRequestBehavior; using Cellm.Services.Configuration; using Cellm.Tools; using Cellm.Tools.FileReader; @@ -93,8 +93,6 @@ private static IServiceCollection ConfigureServices(IServiceCollection services) // Tools services - .AddSingleton() - .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton(); diff --git a/src/Cellm/Tools/FileReader/FileReaderFactory.cs b/src/Cellm/Tools/FileReader/FileReaderFactory.cs index bf812b8..c421ca7 100644 --- a/src/Cellm/Tools/FileReader/FileReaderFactory.cs +++ b/src/Cellm/Tools/FileReader/FileReaderFactory.cs @@ -9,7 +9,7 @@ public FileReaderFactory(IEnumerable readers) _readers = readers; } - public IFileReader GetReader(string filePath) + public IFileReader GetFileReader(string filePath) { return _readers.FirstOrDefault(r => r.CanRead(filePath)) ?? throw new NotSupportedException($"No reader found for file: {filePath}"); diff --git a/src/Cellm/Tools/FileReader/FileReaderRequest.cs b/src/Cellm/Tools/FileReader/FileReaderRequest.cs index 666124e..f8e4aac 100644 --- a/src/Cellm/Tools/FileReader/FileReaderRequest.cs +++ b/src/Cellm/Tools/FileReader/FileReaderRequest.cs @@ -1,7 +1,5 @@ -using System.ComponentModel; using MediatR; namespace Cellm.Tools.FileReader; -[Description("Reads the contents of file and returns plain text.")] -internal record FileReaderRequest([Description("The absolute path to the file.")] string FilePath) : IRequest; \ No newline at end of file +internal record FileReaderRequest(string FilePath) : IRequest; diff --git a/src/Cellm/Tools/FileReader/FileReaderRequestHandler.cs b/src/Cellm/Tools/FileReader/FileReaderRequestHandler.cs index 4a9954c..0f5457a 100644 --- a/src/Cellm/Tools/FileReader/FileReaderRequestHandler.cs +++ b/src/Cellm/Tools/FileReader/FileReaderRequestHandler.cs @@ -2,21 +2,14 @@ namespace Cellm.Tools.FileReader; -internal class FileReaderRequestHandler : IRequestHandler +internal class FileReaderRequestHandler(FileReaderFactory fileReaderFactory) : IRequestHandler { - private readonly FileReaderFactory _fileReaderFactory; - - public FileReaderRequestHandler(FileReaderFactory fileReaderFactory) - { - _fileReaderFactory = fileReaderFactory; - } - public async Task Handle(FileReaderRequest request, CancellationToken cancellationToken) { try { - var reader = _fileReaderFactory.GetReader(request.FilePath); - var content = await reader.ReadContent(request.FilePath, cancellationToken); + var reader = fileReaderFactory.GetFileReader(request.FilePath); + var content = await reader.ReadFile(request.FilePath, cancellationToken); return new FileReaderResponse(content); } catch (ArgumentException ex) diff --git a/src/Cellm/Tools/FileReader/FileReaderResponse.cs b/src/Cellm/Tools/FileReader/FileReaderResponse.cs index 087f248..5c448b2 100644 --- a/src/Cellm/Tools/FileReader/FileReaderResponse.cs +++ b/src/Cellm/Tools/FileReader/FileReaderResponse.cs @@ -1,5 +1,3 @@ -using System.ComponentModel; - namespace Cellm.Tools.FileReader; -internal record FileReaderResponse([Description("The content of the file")] string FileContent); +internal record FileReaderResponse(string FileContent); diff --git a/src/Cellm/Tools/FileReader/IFileReader.cs b/src/Cellm/Tools/FileReader/IFileReader.cs index e29301e..3d4aad2 100644 --- a/src/Cellm/Tools/FileReader/IFileReader.cs +++ b/src/Cellm/Tools/FileReader/IFileReader.cs @@ -2,5 +2,5 @@ internal interface IFileReader { public bool CanRead(string filePath); - public Task ReadContent(string filePath, CancellationToken cancellationToken); + public Task ReadFile(string filePath, CancellationToken cancellationToken); } diff --git a/src/Cellm/Tools/FileReader/PdfReader.cs b/src/Cellm/Tools/FileReader/PdfReader.cs index 28dd439..9924389 100644 --- a/src/Cellm/Tools/FileReader/PdfReader.cs +++ b/src/Cellm/Tools/FileReader/PdfReader.cs @@ -22,7 +22,7 @@ public bool CanRead(string filePath) return Path.GetExtension(filePath).ToLower() is ".pdf"; } - public Task ReadContent(string filePath, CancellationToken cancellationToken) + public Task ReadFile(string filePath, CancellationToken cancellationToken) { var stringBuilder = new StringBuilder(); diff --git a/src/Cellm/Tools/FileReader/TextReader.cs b/src/Cellm/Tools/FileReader/TextReader.cs index 4bc8a79..4cd5052 100644 --- a/src/Cellm/Tools/FileReader/TextReader.cs +++ b/src/Cellm/Tools/FileReader/TextReader.cs @@ -24,12 +24,12 @@ public bool CanRead(string filePath) return _extensions.Contains(Path.GetExtension(filePath).ToLowerInvariant()); } - public async Task ReadContent(string filePath, CancellationToken cancellationToken) + public async Task ReadFile(string filePath, CancellationToken cancellationToken) { using (var stream = File.OpenRead(filePath)) using (var reader = new StreamReader(stream, Encoding.UTF8, true)) { - return await reader.ReadToEndAsync(); + return await reader.ReadToEndAsync(cancellationToken); } } } \ No newline at end of file diff --git a/src/Cellm/Tools/Functions.cs b/src/Cellm/Tools/Functions.cs new file mode 100644 index 0000000..02cdf13 --- /dev/null +++ b/src/Cellm/Tools/Functions.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; +using Cellm.Tools.FileReader; +using Cellm.Tools.Glob; +using MediatR; + +namespace Cellm.Tools; + +/// +/// Provides an adapter between MediatR request handlers and Microsoft.Extensions.AI. +/// This class wraps tools in function definitions suitable for the AIFunctionFactory. +/// +internal class Functions(ISender sender) +{ + [Description("Uses glob patterns to searches for files on the user's disk and returns matching file paths.")] + [return: Description($"The list of file paths that matches {nameof(includePatterns)} and do not match {nameof(excludePatterns)}")] + public async Task GlobRequest( + [Description("The root directory to start the glob search from")] string rootPath, + [Description("The list of glob patterns whose matches will be included in the result")] List includePatterns, + [Description("An optional list of glob patterns whose matches will be excluded from the result")] List? excludePatterns, + CancellationToken cancellationToken) + { + return await sender.Send(new GlobRequest(rootPath, includePatterns, excludePatterns), cancellationToken); + } + + [Description("Reads a file and returns its content as plain text.")] + [return: Description("The content of the file as plain text")] + public async Task FileReaderRequest( + [Description("The absolute path to the file.")] string filePath, + CancellationToken cancellationToken) + { + return await sender.Send(new FileReaderRequest(filePath), cancellationToken); + } +} diff --git a/src/Cellm/Tools/Glob/GlobRequest.cs b/src/Cellm/Tools/Glob/GlobRequest.cs index a76f634..aea28f8 100644 --- a/src/Cellm/Tools/Glob/GlobRequest.cs +++ b/src/Cellm/Tools/Glob/GlobRequest.cs @@ -1,10 +1,5 @@ -using System.ComponentModel; -using MediatR; +using MediatR; namespace Cellm.Tools.Glob; -[Description("Searches for files on the user's disk using glob patterns.")] -internal record GlobRequest( - [Description("The root directory to start the glob search from")] string RootPath, - [Description("List of patterns to include in the search")] List IncludePatterns, - [Description("Optional list of patterns to exclude from the search")] List? ExcludePatterns) : ITool, IRequest; +internal record GlobRequest(string RootPath, List IncludePatterns, List? ExcludePatterns) : IRequest; diff --git a/src/Cellm/Tools/Glob/GlobRequestHandler.cs b/src/Cellm/Tools/Glob/GlobRequestHandler.cs index 2e82528..de94506 100644 --- a/src/Cellm/Tools/Glob/GlobRequestHandler.cs +++ b/src/Cellm/Tools/Glob/GlobRequestHandler.cs @@ -9,7 +9,7 @@ public Task Handle(GlobRequest request, CancellationToken cancella { var matcher = new Matcher(); matcher.AddIncludePatterns(request.IncludePatterns); - matcher.AddExcludePatterns(request.ExcludePatterns ?? new List()); + matcher.AddExcludePatterns(request.ExcludePatterns ?? []); var fileNames = matcher.GetResultsInFullPath(request.RootPath); return Task.FromResult(new GlobResponse(fileNames.ToList())); diff --git a/src/Cellm/Tools/Glob/GlobResponse.cs b/src/Cellm/Tools/Glob/GlobResponse.cs index 65b23ef..6360d37 100644 --- a/src/Cellm/Tools/Glob/GlobResponse.cs +++ b/src/Cellm/Tools/Glob/GlobResponse.cs @@ -1,6 +1,3 @@ -using System.ComponentModel; +namespace Cellm.Tools.Glob; -namespace Cellm.Tools.Glob; - -internal record GlobResponse( - [Description("List of file paths matching the glob patterns")] List FilePaths); +internal record GlobResponse(List FilePaths); diff --git a/src/Cellm/Tools/ITool.cs b/src/Cellm/Tools/ITool.cs deleted file mode 100644 index 57dbcd3..0000000 --- a/src/Cellm/Tools/ITool.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Cellm.Tools; - -public interface ITool -{ -} diff --git a/src/Cellm/Tools/ToolFactory.cs b/src/Cellm/Tools/ToolFactory.cs deleted file mode 100644 index 7582ef2..0000000 --- a/src/Cellm/Tools/ToolFactory.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Reflection; -using Cellm.AddIn.Exceptions; -using Cellm.Prompts; -using Json.More; -using Json.Schema; -using Json.Schema.Generation; - -namespace Cellm.Tools; - -public class ToolFactory -{ - public static Tool CreateTool(Type type) - { - var description = GetDescriptionForType(type); - - var parameterSchemaBuilder = new JsonSchemaBuilder() - .FromType(type) - .Properties(GetPropertiesForType(type)) - .Required(GetRequiredForType(type)) - .AdditionalProperties(false); - - var parameterSchema = parameterSchemaBuilder.Build(); - var parameters = parameterSchema.ToJsonDocument(); - - return new Tool( - type.Name, - description, - parameters - ); - } - private static IReadOnlyDictionary GetPropertiesForType(Type type) - { - return type - .GetProperties() - .ToDictionary( - property => property.Name, - property => new JsonSchemaBuilder() - .FromType(property.PropertyType) - .Description(GetPropertyDescriptionsForType(type, property.Name)) - .Build() - ); - } - - private static string GetPropertyDescriptionsForType(Type type, string propertyName) - { - return type - .GetConstructors() - .First() // Records have a single constructor - .GetParameters() - .Where(property => property.Name == propertyName) - .Select(property => property.GetCustomAttribute()?.Description) - .FirstOrDefault() ?? throw new CellmException($"Cannot get description of {type.Name} property {propertyName}."); - } - - public static List GetRequiredForType(Type type) - { - return type - .GetConstructors() - .First() // Records have a single constructor - .GetParameters() - .Where(p => !IsNullableType(p.ParameterType)) - .Select(p => p.Name!) - .ToList(); - } - - private static bool IsNullableType(Type type) - { - // Check if it's a nullable reference type (marked with ?) - if (type.IsValueType == false) - { - var nullabilityInfo = type.GetCustomAttribute(); - if (nullabilityInfo != null) - { - return true; - } - } - - // Check if it's Nullable - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - return true; - } - - return false; - } - - private static string GetDescriptionForType(Type type) - { - var descriptionAttribute = type.GetCustomAttribute(); - return descriptionAttribute?.Description ?? throw new ArgumentException($"Cannot get tool description for {type.Name}."); - } -} \ No newline at end of file diff --git a/src/Cellm/Tools/ToolRunner.cs b/src/Cellm/Tools/ToolRunner.cs deleted file mode 100644 index f36b25e..0000000 --- a/src/Cellm/Tools/ToolRunner.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Cellm.Models; -using Cellm.Prompts; -using Cellm.Tools.FileReader; -using Cellm.Tools.Glob; -using MediatR; - -namespace Cellm.Tools; - -internal class ToolRunner -{ - private readonly ISender _sender; - private readonly Serde _serde; - private readonly ToolFactory _toolFactory; - private readonly IEnumerable _toolTypes; - - public ToolRunner(ISender sender, Serde serde, ToolFactory toolFactory) - { - _sender = sender; - _serde = serde; - _toolFactory = toolFactory; - _toolTypes = new List() { - typeof(GlobRequest), - typeof(FileReaderRequest) - }; - } - - public List GetTools() - { - return _toolTypes.Select(ToolFactory.CreateTool).ToList(); - } - - public async Task Run(ToolCall toolCall) - { - return toolCall.Name switch - { - nameof(GlobRequest) => await Run(toolCall.Arguments), - nameof(FileReaderRequest) => await Run(toolCall.Arguments), - _ => throw new ArgumentException($"Unsupported tool: {toolCall.Name}") - }; - } - - private async Task Run(string arguments) - where T : notnull - { - var request = _serde.Deserialize(arguments); - var response = await _sender.Send(request); - return _serde.Serialize(response); - } -} diff --git a/src/Cellm/appsettings.json b/src/Cellm/appsettings.json index 873897d..ad34270 100644 --- a/src/Cellm/appsettings.json +++ b/src/Cellm/appsettings.json @@ -17,7 +17,8 @@ "DefaultTemperature": 0, "MaxOutputTokens": 256, "HttpTimeoutInSeconds": 600, - "CacheTimeoutInSeconds": 3600 + "CacheTimeoutInSeconds": 3600, + "EnableTools": true }, "RateLimiterConfiguration": { "TokenLimit": 4, diff --git a/src/Cellm/packages.lock.json b/src/Cellm/packages.lock.json index ea905e9..ead687e 100644 --- a/src/Cellm/packages.lock.json +++ b/src/Cellm/packages.lock.json @@ -46,6 +46,61 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, + "Microsoft.Extensions.AI": { + "type": "Direct", + "requested": "[9.0.0-preview.9.24556.5, )", + "resolved": "9.0.0-preview.9.24556.5", + "contentHash": "71WuoNoQObf3OVWFMuGt7WB/iLlHxobH7aUV7yKVO3/p2+JbAOXXyzcD4EoLsA/40HYZmDSXVKAzIZ6co+0vNg==", + "dependencies": { + "Microsoft.Extensions.AI.Abstractions": "9.0.0-preview.9.24556.5", + "Microsoft.Extensions.Caching.Abstractions": "9.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "9.0.0", + "System.Diagnostics.DiagnosticSource": "9.0.0", + "System.Text.Json": "9.0.0" + } + }, + "Microsoft.Extensions.AI.Abstractions": { + "type": "Direct", + "requested": "[9.0.0-preview.9.24556.5, )", + "resolved": "9.0.0-preview.9.24556.5", + "contentHash": "h+sY5wkFV7FCFN4KURGiC2yTwXysLtFCZW/ndx9urCMfRyHt+2Z3YW3NBGjXYbAMCB+BQbkzc2aQ9SLKCCzgVA==" + }, + "Microsoft.Extensions.AI.Ollama": { + "type": "Direct", + "requested": "[9.0.0-preview.9.24556.5, )", + "resolved": "9.0.0-preview.9.24556.5", + "contentHash": "Wsn1LjuI6Z3opqPHauvNgTAt/oR9GvyLzKxhavh7QP19rLtLhxNo7wtBgIlmOSz2i3DujOx6t6UH1ZqJpAzWEw==", + "dependencies": { + "Microsoft.Extensions.AI.Abstractions": "9.0.0-preview.9.24556.5", + "System.Net.Http.Json": "8.0.1", + "System.Text.Json": "8.0.5" + } + }, + "Microsoft.Extensions.AI.OpenAI": { + "type": "Direct", + "requested": "[9.0.0-preview.9.24556.5, )", + "resolved": "9.0.0-preview.9.24556.5", + "contentHash": "VVNISh8h6iq4yTTqG4qaCam8DjdCThe4TE35wPLSkvRNXivAjJ+1Cu+yzRc9pB3Hm4ot0Kko6C0u8+CiXJkE0Q==", + "dependencies": { + "Microsoft.Extensions.AI.Abstractions": "9.0.0-preview.9.24556.5", + "OpenAI": "2.0.0", + "System.Memory.Data": "8.0.1", + "System.Text.Json": "8.0.5" + } + }, + "Microsoft.Extensions.Caching.Hybrid": { + "type": "Direct", + "requested": "[9.0.0-preview.9.24556.5, )", + "resolved": "9.0.0-preview.9.24556.5", + "contentHash": "ktYy1ZK6V1mqdHQdZIVjHiWZG/pPZmjDa9SWmlMh9uUUPgOeFT+Uzfh6UUu6Fty4N7jsNKK81WL2dDkXr0nfZw==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "9.0.0", + "Microsoft.Extensions.Caching.Memory": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "9.0.0", + "Microsoft.Extensions.Options": "9.0.0" + } + }, "Microsoft.Extensions.Caching.Memory": { "type": "Direct", "requested": "[9.0.0, )", @@ -78,8 +133,7 @@ "Microsoft.Extensions.Configuration": "8.0.0", "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "8.0.1", - "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", - "System.Text.Json": "8.0.5" + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0" } }, "Microsoft.Extensions.DependencyInjection": { @@ -105,6 +159,7 @@ "dependencies": { "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Diagnostics": "8.0.0", "Microsoft.Extensions.Logging": "8.0.0", "Microsoft.Extensions.Logging.Abstractions": "8.0.0", "Microsoft.Extensions.Options": "8.0.0" @@ -128,13 +183,11 @@ "resolved": "9.0.0", "contentHash": "yDZ4zsjl7N0K+R/1QTNpXBd79Kaf4qNLHtjk4NaG82UtNg2Z6etJywwv6OarOv3Rp7ocU7uIaRY4CrzHRO/d3w==", "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "9.0.0", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", "Microsoft.Extensions.Logging": "9.0.0", "Microsoft.Extensions.Logging.Abstractions": "9.0.0", "Microsoft.Extensions.Logging.Configuration": "9.0.0", "Microsoft.Extensions.Options": "9.0.0", - "System.Buffers": "4.5.1", "System.Text.Json": "9.0.0" } }, @@ -156,8 +209,7 @@ "contentHash": "y2146b3jrPI3Q0lokKXdKLpmXqakYbDIPDV6r3M8SqvSf45WwOTzkyfDpxnZXJsJQEpAsAqjUq5Pu8RCJMjubg==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", - "Microsoft.Extensions.Primitives": "9.0.0", - "System.ComponentModel.Annotations": "5.0.0" + "Microsoft.Extensions.Primitives": "9.0.0" } }, "Microsoft.Extensions.Options.ConfigurationExtensions": { @@ -185,8 +237,9 @@ "resolved": "4.12.1", "contentHash": "0u8QJxh58+i9D1EKBpcH87J8iAOAYB0oLzyWKMIW1NSUHND19pf9ZMG5gE/F4/iNRFefZ7GAVMyNpepg+mmL7w==", "dependencies": { - "Microsoft.Extensions.Http": "6.0.0", - "Microsoft.Extensions.Logging.Configuration": "6.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.Http": "8.0.0", + "Microsoft.Extensions.Logging.Configuration": "8.0.0", "Sentry": "4.12.1" } }, @@ -213,10 +266,7 @@ "Json.More.Net": { "type": "Transitive", "resolved": "2.0.1.2", - "contentHash": "uF3QeiaXEfH92emz0/BWUiNtMSfxIIvgynuB0Bf1vF4s8eWTcZitBx9l+g/FDaJk5XxqBv9buQXizXKQcXFG1w==", - "dependencies": { - "System.Text.Json": "8.0.0" - } + "contentHash": "uF3QeiaXEfH92emz0/BWUiNtMSfxIIvgynuB0Bf1vF4s8eWTcZitBx9l+g/FDaJk5XxqBv9buQXizXKQcXFG1w==" }, "JsonPointer.Net": { "type": "Transitive", @@ -240,19 +290,6 @@ "resolved": "2.0.1", "contentHash": "FYv95bNT4UwcNA+G/J1oX5OpRiSUxteXaUt2BJbRSdRNiIUNbggJF69wy6mnk2wYToaanpdXZdCwVylt96MpwQ==" }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "9.0.0", - "contentHash": "owmu2Cr3IQ8yQiBleBHlGk8dSQ12oaF2e7TpzwJKEl4m84kkZJjEY1n33L67Y3zM5jPOjmmbdHjbfiL0RqcMRQ==" - }, - "Microsoft.Bcl.TimeProvider": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "C7kWHJnMRY7EvJev2S8+yJHZ1y7A4ZlLbA4NE+O23BDIAN5mHeqND1m+SKv1ChRS5YlCDW7yAMUe7lttRsJaAA==", - "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "8.0.0" - } - }, "Microsoft.Diagnostics.NETCore.Client": { "type": "Transitive", "resolved": "0.2.510501", @@ -276,8 +313,7 @@ "resolved": "9.0.0", "contentHash": "FPWZAa9c0H4dvOj351iR1jkUIs4u9ykL4Bm592yhjDyO5lCoWd+TMAHx2EMbarzUvCvgjWjJIoC6//Q9kH6YhA==", "dependencies": { - "Microsoft.Extensions.Primitives": "9.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" + "Microsoft.Extensions.Primitives": "9.0.0" } }, "Microsoft.Extensions.Compliance.Abstractions": { @@ -355,8 +391,7 @@ "resolved": "8.8.0", "contentHash": "K9jlnvIbkYvHRAwxl8WjFkIU7D/5PYAeVmDMAN6Y4IQyWyBUT/xMotYwYGRFAO2kiPPJhIIj7a9VI2p7ydakkg==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", - "System.Collections.Immutable": "8.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1" } }, "Microsoft.Extensions.FileProviders.Abstractions": { @@ -408,8 +443,7 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.0", "Microsoft.Extensions.Logging.Abstractions": "9.0.0", - "Microsoft.Extensions.Options": "9.0.0", - "System.Diagnostics.DiagnosticSource": "9.0.0" + "Microsoft.Extensions.Options": "9.0.0" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -418,9 +452,7 @@ "contentHash": "g0UfujELzlLbHoVG8kPKVBaW470Ewi+jnptGS9KUi6jcb+k2StujtK3m26DFSGGwQ/+bVgZfsWqNzlP6YOejvw==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", - "System.Buffers": "4.5.1", - "System.Diagnostics.DiagnosticSource": "9.0.0", - "System.Memory": "4.5.5" + "System.Diagnostics.DiagnosticSource": "9.0.0" } }, "Microsoft.Extensions.Logging.Configuration": { @@ -446,11 +478,7 @@ "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "9.0.0", - "contentHash": "N3qEBzmLMYiASUlKxxFIISP4AiwuPTHF5uCh+2CWSwwzAJiIYx0kBJsS30cp1nvhSySFAVi30jecD307jV+8Kg==", - "dependencies": { - "System.Memory": "4.5.5", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } + "contentHash": "N3qEBzmLMYiASUlKxxFIISP4AiwuPTHF5uCh+2CWSwwzAJiIYx0kBJsS30cp1nvhSySFAVi30jecD307jV+8Kg==" }, "Microsoft.Extensions.Resilience": { "type": "Transitive", @@ -470,13 +498,11 @@ "resolved": "8.8.0", "contentHash": "3LMXqE65Sv/u160bsG7/meI55peTi68DZ5eAlOb+0FSHdg1rBwn7sNDh6arW135sOoIp/28CsZIigIX5ZPvXTA==", "dependencies": { - "Microsoft.Bcl.TimeProvider": "8.0.1", "Microsoft.Extensions.AmbientMetadata.Application": "8.8.0", "Microsoft.Extensions.DependencyInjection.AutoActivation": "8.8.0", "Microsoft.Extensions.Logging.Configuration": "8.0.0", "Microsoft.Extensions.ObjectPool": "8.0.8", - "Microsoft.Extensions.Telemetry.Abstractions": "8.8.0", - "System.Collections.Immutable": "8.0.0" + "Microsoft.Extensions.Telemetry.Abstractions": "8.8.0" } }, "Microsoft.Extensions.Telemetry.Abstractions": { @@ -495,14 +521,20 @@ "resolved": "3.0.0", "contentHash": "irv0HuqoH8Ig5i2fO+8dmDNdFdsrO+DoQcedwIlb810qpZHBNQHZLW7C/AHBQDgLLpw2T96vmMAy/aE4Yj55Sg==" }, - "Polly.Core": { + "OpenAI": { "type": "Transitive", - "resolved": "8.4.1", - "contentHash": "bg4kE7mFwXc6FJ8NLknTgVgLAMlbToWC7vpdqAITv8lPzKpp9v7aWJPc04GRoZQaJhVY/tdr8K2/VW2aTmaA1Q==", + "resolved": "2.0.0", + "contentHash": "WI9e5tC15ZBt02scCp2gcHrjxQRVX2Ws3eUu/YsICqellH3MwdRggGujSZg69oBJMtk1AYmqb9l08ix0l5AcqQ==", "dependencies": { - "Microsoft.Bcl.TimeProvider": "8.0.0" + "System.ClientModel": "1.1.0", + "System.Diagnostics.DiagnosticSource": "6.0.1" } }, + "Polly.Core": { + "type": "Transitive", + "resolved": "8.4.1", + "contentHash": "bg4kE7mFwXc6FJ8NLknTgVgLAMlbToWC7vpdqAITv8lPzKpp9v7aWJPc04GRoZQaJhVY/tdr8K2/VW2aTmaA1Q==" + }, "Polly.Extensions": { "type": "Transitive", "resolved": "8.4.1", @@ -527,86 +559,53 @@ "resolved": "4.12.1", "contentHash": "OLf7885OKHWLaTLTyw884mwOT4XKCWj2Hz5Wuz/TJemJqXwCIdIljkJBIoeHviRUPvtB7ulDgeYXf/Z7ScToSA==" }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, - "System.Collections.Immutable": { + "System.ClientModel": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "resolved": "1.1.0", + "contentHash": "UocOlCkxLZrG2CKMAAImPcldJTxeesHnHGHwhJ0pNlZEvEXcWKuQvVOER2/NiOkJGRJk978SNdw3j6/7O9H1lg==", "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" + "System.Memory.Data": "1.0.2", + "System.Text.Json": "6.0.9" } }, - "System.ComponentModel.Annotations": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "9.0.0", - "contentHash": "ddppcFpnbohLWdYKr/ZeLZHmmI+DXFgZ3Snq+/E7SwcdW4UnvxmaugkwGywvGVWkHPGCSZjCP+MLzu23AL5SDw==", - "dependencies": { - "System.Memory": "4.5.5", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } + "contentHash": "ddppcFpnbohLWdYKr/ZeLZHmmI+DXFgZ3Snq+/E7SwcdW4UnvxmaugkwGywvGVWkHPGCSZjCP+MLzu23AL5SDw==" }, "System.IO.Pipelines": { "type": "Transitive", "resolved": "9.0.0", - "contentHash": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", - "dependencies": { - "System.Buffers": "4.5.1", - "System.Memory": "4.5.5", - "System.Threading.Tasks.Extensions": "4.5.4" - } + "contentHash": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==" }, - "System.Memory": { + "System.Memory.Data": { "type": "Transitive", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" + "resolved": "8.0.1", + "contentHash": "BVYuec3jV23EMRDeR7Dr1/qhx7369dZzJ9IWy2xylvb4YfXsrUxspWc4UWYid/tj4zZK58uGZqn2WQiaDMhmAg==" }, - "System.Runtime.CompilerServices.Unsafe": { + "System.Net.Http.Json": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + "resolved": "8.0.1", + "contentHash": "F423ZLoJFYg1s6iA+Y7BLflVKjEK5XEA2+Z9CHbxJEUtS3+R5pgnFN499QzriRjYpOu6kS2Crd2YBkOFDHrblg==" }, "System.Text.Encodings.Web": { "type": "Transitive", "resolved": "9.0.0", - "contentHash": "e2hMgAErLbKyUUwt18qSBf9T5Y+SFAL3ZedM8fLupkVj8Rj2PZ9oxQ37XX2LF8fTO1wNIxvKpihD7Of7D/NxZw==", - "dependencies": { - "System.Buffers": "4.5.1", - "System.Memory": "4.5.5", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } + "contentHash": "e2hMgAErLbKyUUwt18qSBf9T5Y+SFAL3ZedM8fLupkVj8Rj2PZ9oxQ37XX2LF8fTO1wNIxvKpihD7Of7D/NxZw==" }, "System.Text.Json": { "type": "Transitive", "resolved": "9.0.0", "contentHash": "js7+qAu/9mQvnhA4EfGMZNEzXtJCDxgkgj8ohuxq/Qxv+R56G+ljefhiJHOxTNiw54q8vmABCWUwkMulNdlZ4A==", "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "9.0.0", - "System.Buffers": "4.5.1", "System.IO.Pipelines": "9.0.0", - "System.Memory": "4.5.5", - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "9.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" + "System.Text.Encodings.Web": "9.0.0" } }, "System.Threading.RateLimiting": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "7mu9v0QDv66ar3DpGSZHg9NuNcxDaaAcnMULuZlaTpP9+hwXhrxNGsF5GmLkSHxFdb5bBc1TzeujsRgTrPWi+Q==" - }, - "System.Threading.Tasks.Extensions": { - "type": "Transitive", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" } } } From bc9bcec16ca96a985aeae0755b1b51b8816be476 Mon Sep 17 00:00:00 2001 From: Kasper Marstal Date: Thu, 21 Nov 2024 23:05:56 +0100 Subject: [PATCH 5/6] fix: Build error --- src/Cellm/Models/Llamafile/LlamafileRequestHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cellm/Models/Llamafile/LlamafileRequestHandler.cs b/src/Cellm/Models/Llamafile/LlamafileRequestHandler.cs index 8a6f5d7..f52aecc 100644 --- a/src/Cellm/Models/Llamafile/LlamafileRequestHandler.cs +++ b/src/Cellm/Models/Llamafile/LlamafileRequestHandler.cs @@ -57,8 +57,8 @@ public LlamafileRequestHandler(IOptions cellmConfiguration, public async Task Handle(LlamafileRequest request, CancellationToken cancellationToken) { - // Download model and start Llamafile on first call - var llamafile = await _llamafiles[request.Prompt.Model ?? _llamafileConfiguration.DefaultModel]; + // Start server on first call + var llamafile = await _llamafiles[request.Prompt.Options.ModelId ?? _llamafileConfiguration.DefaultModel]; var openAiResponse = await _sender.Send(new OpenAiRequest(request.Prompt, nameof(Llamafile), llamafile.BaseAddress), cancellationToken); From 0ffb3c8acc56551f95311721830748338c355f16 Mon Sep 17 00:00:00 2001 From: Kasper Marstal Date: Thu, 21 Nov 2024 23:12:37 +0100 Subject: [PATCH 6/6] style: dotnet format --- src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs | 2 +- src/Cellm/Services/ServiceLocator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs b/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs index fbdf857..0eeec9f 100644 --- a/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs +++ b/src/Cellm/Models/ModelRequestBehavior/ToolBehavior.cs @@ -29,7 +29,7 @@ public async Task Handle(TRequest request, RequestHandlerDelegate