diff --git a/LangChain.sln b/LangChain.sln index 7c286c68..e484dd99 100644 --- a/LangChain.sln +++ b/LangChain.sln @@ -172,16 +172,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Automat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Automatic1111.IntegrationTests", "src\tests\LangChain.Providers.Automatic1111.IntegrationTests\LangChain.Providers.Automatic1111.IntegrationTests.csproj", "{A6CF79BC-8365-46E8-9230-1A4AD615D40B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Bedrock.IntegrationTests", "src\tests\LangChain.Providers.Bedrock.IntegrationTests\LangChain.Providers.Bedrock.IntegrationTests.csproj", "{73C76E80-95C5-4C96-A319-4F32043C903E}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Bedrock", "src\libs\Providers\LangChain.Providers.Bedrock\LangChain.Providers.Bedrock.csproj", "{67985CCB-F606-41F8-9D36-513459F58882}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Amazon.IntegrationTests", "src\tests\LangChain.Providers.Bedrock.IntegrationTests\LangChain.Providers.Amazon.IntegrationTests.csproj", "{73C76E80-95C5-4C96-A319-4F32043C903E}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Amazon.Bedrock", "src\libs\Providers\LangChain.Providers.Amazon.Bedrock\LangChain.Providers.Amazon.Bedrock.csproj", "{67985CCB-F606-41F8-9D36-513459F58882}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Amazon.SageMaker", "src\libs\Providers\LangChain.Providers.Amazon.Sagemaker\LangChain.Providers.Amazon.SageMaker.csproj", "{F1AD6925-219C-4B17-B8D8-0ACCA6F401C4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Providers.Bedrock.IntegrationTests", "src\tests\LangChain.Providers.Bedrock.IntegrationTests\LangChain.Providers.Bedrock.IntegrationTests.csproj", "{4F37D6C5-38C9-485B-AD87-2691EED225E1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -416,10 +414,6 @@ Global {BA701280-0BEB-4DA4-92B3-9C777082C2AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {BA701280-0BEB-4DA4-92B3-9C777082C2AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {BA701280-0BEB-4DA4-92B3-9C777082C2AF}.Release|Any CPU.Build.0 = Release|Any CPU - {73C76E80-95C5-4C96-A319-4F32043C903E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73C76E80-95C5-4C96-A319-4F32043C903E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73C76E80-95C5-4C96-A319-4F32043C903E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73C76E80-95C5-4C96-A319-4F32043C903E}.Release|Any CPU.Build.0 = Release|Any CPU {67985CCB-F606-41F8-9D36-513459F58882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67985CCB-F606-41F8-9D36-513459F58882}.Debug|Any CPU.Build.0 = Debug|Any CPU {67985CCB-F606-41F8-9D36-513459F58882}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -428,6 +422,10 @@ Global {F1AD6925-219C-4B17-B8D8-0ACCA6F401C4}.Debug|Any CPU.Build.0 = Debug|Any CPU {F1AD6925-219C-4B17-B8D8-0ACCA6F401C4}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1AD6925-219C-4B17-B8D8-0ACCA6F401C4}.Release|Any CPU.Build.0 = Release|Any CPU + {4F37D6C5-38C9-485B-AD87-2691EED225E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F37D6C5-38C9-485B-AD87-2691EED225E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F37D6C5-38C9-485B-AD87-2691EED225E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F37D6C5-38C9-485B-AD87-2691EED225E1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -496,8 +494,8 @@ Global {4913844F-74EC-4E74-AE8A-EA825569E6BA} = {E55391DE-F8F3-4CC2-A0E3-2406C76E9C68} {BF4C7B87-0997-4208-84EF-D368DF7B9861} = {E55391DE-F8F3-4CC2-A0E3-2406C76E9C68} {A6CF79BC-8365-46E8-9230-1A4AD615D40B} = {FDEE2E22-C239-4921-83B2-9797F765FD6A} - {73C76E80-95C5-4C96-A319-4F32043C903E} = {FDEE2E22-C239-4921-83B2-9797F765FD6A} {67985CCB-F606-41F8-9D36-513459F58882} = {E55391DE-F8F3-4CC2-A0E3-2406C76E9C68} + {4F37D6C5-38C9-485B-AD87-2691EED225E1} = {FDEE2E22-C239-4921-83B2-9797F765FD6A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5C00D0F1-6138-4ED9-846B-97E43D6DFF1C} diff --git a/examples/LangChain.Samples.Memory/Program.cs b/examples/LangChain.Samples.Memory/Program.cs index e6fb0447..cccd2ea2 100644 --- a/examples/LangChain.Samples.Memory/Program.cs +++ b/examples/LangChain.Samples.Memory/Program.cs @@ -47,7 +47,7 @@ The following is a friendly conversation between a human and an AI. Console.WriteLine(); Console.Write("Human: "); - var input = Console.ReadLine(); + var input = Console.ReadLine() ?? string.Empty; if (input == "exit") { break; @@ -122,7 +122,7 @@ private static string PromptForChoice(string[] choiceTexts) Console.WriteLine(); Console.Write("Enter choice: "); - string choiceEntry = Console.ReadLine(); + string choiceEntry = Console.ReadLine() ?? string.Empty; if (int.TryParse(choiceEntry, out int choiceIndex)) { string choiceText = choiceTexts[choiceIndex]; diff --git a/src/libs/Databases/LangChain.Databases.Sqlite/SQLiteVectorStore.cs b/src/libs/Databases/LangChain.Databases.Sqlite/SQLiteVectorStore.cs index 342e8f7c..20fec9ff 100644 --- a/src/libs/Databases/LangChain.Databases.Sqlite/SQLiteVectorStore.cs +++ b/src/libs/Databases/LangChain.Databases.Sqlite/SQLiteVectorStore.cs @@ -41,7 +41,7 @@ public static async Task CreateIndexFromDocuments( return index; } - public static SQLIteVectorStoreOptions DefaultOptions = new SQLIteVectorStoreOptions(); + public static SQLIteVectorStoreOptions DefaultOptions { get; } = new(); /// /// If database does not exists, it loads documents from the documentsSource, creates an index from these documents and returns the created index. @@ -59,14 +59,16 @@ public static async Task GetIndex( TextSplitter textSplitter = new RecursiveCharacterTextSplitter(chunkSize: options.ChunkSize, chunkOverlap: options.ChunkOverlap); - if (!System.IO.File.Exists("vectors.db")) + if (!System.IO.File.Exists("vectors.db") && documentsSource != null) { - var documents = await documentsSource.LoadAsync(); - return await SQLiteVectorStore.CreateIndexFromDocuments(embeddings, documents, options.Filename, options.TableName, textSplitter: textSplitter); + var documents = await documentsSource.LoadAsync().ConfigureAwait(false); + return await CreateIndexFromDocuments(embeddings, documents, options.Filename, options.TableName, textSplitter: textSplitter).ConfigureAwait(false); } +#pragma warning disable CA2000 var vectorStore = new SQLiteVectorStore(options.Filename, options.TableName, embeddings); +#pragma warning restore CA2000 var index = new VectorStoreIndexWrapper(vectorStore); return index; } diff --git a/src/libs/Extensions/LangChain.Extensions.Docker/Chain.cs b/src/libs/Extensions/LangChain.Extensions.Docker/Chain.cs index 380e490a..3ca5d34e 100644 --- a/src/libs/Extensions/LangChain.Extensions.Docker/Chain.cs +++ b/src/libs/Extensions/LangChain.Extensions.Docker/Chain.cs @@ -1,6 +1,4 @@ -using LangChain.Chains.HelperChains; - -namespace LangChain.Extensions.Docker; +namespace LangChain.Extensions.Docker; /// /// @@ -11,12 +9,17 @@ public static class Chain /// /// /// - /// + /// /// - /// + /// /// /// - public static DockerChain RunCodeInDocker(string image= "python:3.10", string arguments = "main.py", string command = "python", string? attachVolume=null, string outputKey = "result") + public static DockerChain RunCodeInDocker( + string image= "python:3.10", + string arguments = "main.py", + string command = "python", + string? attachVolume = null, + string outputKey = "result") { return new DockerChain(image, arguments, command, attachVolume, outputKey); } diff --git a/src/libs/Extensions/LangChain.Extensions.Docker/DockerChain.cs b/src/libs/Extensions/LangChain.Extensions.Docker/DockerChain.cs index 59625930..83713998 100644 --- a/src/libs/Extensions/LangChain.Extensions.Docker/DockerChain.cs +++ b/src/libs/Extensions/LangChain.Extensions.Docker/DockerChain.cs @@ -44,8 +44,14 @@ public void Report(JSONMessage value) /// /// /// + /// /// - public DockerChain(string image= "python:3", string arguments="main.py", string command="python", string? attachVolume=null, string outputKey="result") + public DockerChain( + string image= "python:3", + string arguments="main.py", + string command="python", + string? attachVolume=null, + string outputKey="result") { Image = image; Arguments = arguments; @@ -77,7 +83,9 @@ await _client.Images.CreateImageAsync(new ImagesCreateParameters() if (AttachVolume != null) { - var absolutePath = Path.GetFullPath(AttachVolume).Replace("\\","/").Replace(":",""); + var absolutePath = Path.GetFullPath(AttachVolume) + .Replace("\\","/", StringComparison.Ordinal) + .Replace(":","", StringComparison.Ordinal); binds.Add($"/{absolutePath}:/app"); } diff --git a/src/libs/LangChain.Core/Chains/StackableChains/Agents/ReActAgentExecutorChain.cs b/src/libs/LangChain.Core/Chains/StackableChains/Agents/ReActAgentExecutorChain.cs index 916747c6..345d9b9d 100644 --- a/src/libs/LangChain.Core/Chains/StackableChains/Agents/ReActAgentExecutorChain.cs +++ b/src/libs/LangChain.Core/Chains/StackableChains/Agents/ReActAgentExecutorChain.cs @@ -1,4 +1,5 @@ -using LangChain.Abstractions.Chains.Base; +using System.Globalization; +using LangChain.Abstractions.Chains.Base; using LangChain.Abstractions.Schema; using LangChain.Chains.HelperChains; using LangChain.Chains.StackableChains.ReAct; @@ -134,8 +135,8 @@ protected override async Task InternalCall(IChainValues values) if (res.Value[ReActAnswer] is AgentAction) { var action = (AgentAction)res.Value[ReActAnswer]; - var tool = _tools[action.Action.ToLower()]; - var toolRes = await tool.ToolTask(action.ActionInput); + var tool = _tools[action.Action.ToLower(CultureInfo.InvariantCulture)]; + var toolRes = await tool.ToolTask(action.ActionInput).ConfigureAwait(false); await _conversationBufferMemory.ChatHistory.AddMessage(new Message("Observation: " + toolRes, MessageRole.System)) .ConfigureAwait(false); await _conversationBufferMemory.ChatHistory.AddMessage(new Message("Thought:", MessageRole.System)) diff --git a/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/Classes/GoogleResults.cs b/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/Classes/GoogleResults.cs index 1cb02a52..7a6b22c9 100644 --- a/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/Classes/GoogleResults.cs +++ b/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/Classes/GoogleResults.cs @@ -6,10 +6,11 @@ public class GoogleResult { public class Item { - public string title { get; set; } - public string link { get; set; } - public string snippet { get; set; } + public string title { get; set; } = string.Empty; + public string link { get; set; } = string.Empty; + public string snippet { get; set; } = string.Empty; } - public List items { get; set; } + + public List items { get; set; } = []; } \ No newline at end of file diff --git a/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/GoogleCustomSearchTool.cs b/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/GoogleCustomSearchTool.cs index 1ef5aaea..dc1280dc 100644 --- a/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/GoogleCustomSearchTool.cs +++ b/src/libs/LangChain.Core/Chains/StackableChains/Agents/Tools/BuiltIn/GoogleCustomSearchTool.cs @@ -40,17 +40,17 @@ void SaveCachedAnswer(string prompt, string answer) File.WriteAllText(file, answer); } - public override async Task ToolTask(string input, CancellationToken token = default) + public override async Task ToolTask(string input, CancellationToken cancellationToken = default) { - string responseString; + string? responseString; if (!useCache||(responseString = GetCachedAnswer(input))==null) { using var httpClient = new HttpClient(); httpClient.BaseAddress = new Uri("https://www.googleapis.com"); var response = await httpClient.GetAsync( - $"/customsearch/v1?key={key}&cx={cx}&q={input}", token).ConfigureAwait(false); + new Uri($"/customsearch/v1?key={key}&cx={cx}&q={input}"), cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); - responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + responseString = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); } diff --git a/src/libs/LangChain.Core/Chains/StackableChains/Extensions/HookExtension.cs b/src/libs/LangChain.Core/Chains/StackableChains/Extensions/HookExtension.cs index e3d7e3ef..b1e4ccec 100644 --- a/src/libs/LangChain.Core/Chains/StackableChains/Extensions/HookExtension.cs +++ b/src/libs/LangChain.Core/Chains/StackableChains/Extensions/HookExtension.cs @@ -7,6 +7,8 @@ public static class HookExtension { public static T Hook(this T chain, Action hook) where T : BaseStackableChain { + chain = chain ?? throw new ArgumentNullException(nameof(chain)); + chain.SetHook(hook); return chain; } diff --git a/src/libs/LangChain.Core/Chains/StackableChains/ExtractCodeChain.cs b/src/libs/LangChain.Core/Chains/StackableChains/ExtractCodeChain.cs index e17f61d2..8d954b7c 100644 --- a/src/libs/LangChain.Core/Chains/StackableChains/ExtractCodeChain.cs +++ b/src/libs/LangChain.Core/Chains/StackableChains/ExtractCodeChain.cs @@ -19,7 +19,7 @@ string ExtractCode(string md) var inCode = false; foreach (var line in lines) { - if (line.StartsWith("```")) + if (line.StartsWith("```", StringComparison.OrdinalIgnoreCase)) { inCode = !inCode; continue; @@ -43,7 +43,7 @@ string ExtractCode(string md) protected override Task InternalCall(IChainValues values) { - + values = values ?? throw new ArgumentNullException(nameof(values)); if (values.Value[InputKeys[0]] is string text) { diff --git a/src/libs/LangChain.Core/Chains/StackableChains/LoadMemoryChain.cs b/src/libs/LangChain.Core/Chains/StackableChains/LoadMemoryChain.cs index f36b3f56..5d460300 100644 --- a/src/libs/LangChain.Core/Chains/StackableChains/LoadMemoryChain.cs +++ b/src/libs/LangChain.Core/Chains/StackableChains/LoadMemoryChain.cs @@ -22,7 +22,7 @@ protected override Task InternalCall(IChainValues values) { values = values ?? throw new ArgumentNullException(nameof(values)); - string memoryVariableName = _chatMemory.MemoryVariables.FirstOrDefault(); + var memoryVariableName = _chatMemory.MemoryVariables.FirstOrDefault(); if (memoryVariableName == null) { throw new InvalidOperationException("Missing memory variable name"); diff --git a/src/libs/LangChain.Core/LangChain.Core.csproj b/src/libs/LangChain.Core/LangChain.Core.csproj index bbb79569..a36352c8 100644 --- a/src/libs/LangChain.Core/LangChain.Core.csproj +++ b/src/libs/LangChain.Core/LangChain.Core.csproj @@ -3,7 +3,7 @@ net4.6.2;netstandard2.0;net6.0;net7.0;net8.0 LangChain - $(NoWarn);CA1031;CA1822;CA1307;CA1002;CA1303;CA1003;CA1724 + $(NoWarn);CA1031;CA1822;CA1307;CA1002;CA1303;CA1003;CA1724;CA1034;CA1849 $(NoWarn);CA2227;CA2214;CA1040;CA1812;CA1720;CS9107 $(NoWarn);CA1308;CA1862;CA1510;CA1850;CA1305;CA1725 diff --git a/src/libs/LangChain.Core/Memory/FileChatMessageHistory.cs b/src/libs/LangChain.Core/Memory/FileChatMessageHistory.cs index d4af1ce2..003e78ce 100644 --- a/src/libs/LangChain.Core/Memory/FileChatMessageHistory.cs +++ b/src/libs/LangChain.Core/Memory/FileChatMessageHistory.cs @@ -58,12 +58,21 @@ private async Task SaveMessages() await Task.Run(() => File.WriteAllText(MessagesFilePath, json)).ConfigureAwait(false); } - private async Task LoadMessages() + private Task LoadMessages() { - if (File.Exists(MessagesFilePath)) + try { - string json = await Task.Run(() => File.ReadAllText(MessagesFilePath)).ConfigureAwait(false); - _messages = JsonSerializer.Deserialize>(json); + if (File.Exists(MessagesFilePath)) + { + string json = File.ReadAllText(MessagesFilePath); + _messages = JsonSerializer.Deserialize>(json) ?? new List(); + } + + return Task.CompletedTask; + } + catch (Exception ex) + { + return Task.FromException(ex); } } } \ No newline at end of file diff --git a/src/libs/LangChain.Core/Memory/MessageSummarizer.cs b/src/libs/LangChain.Core/Memory/MessageSummarizer.cs index d9acbcb4..be90625b 100644 --- a/src/libs/LangChain.Core/Memory/MessageSummarizer.cs +++ b/src/libs/LangChain.Core/Memory/MessageSummarizer.cs @@ -53,6 +53,6 @@ public async Task Summarize(IEnumerable newMessages, string exi | Template(SummaryPrompt) | LLM(Model); - return await chain.Run("text").ConfigureAwait(false); + return await chain.Run("text").ConfigureAwait(false) ?? string.Empty; } } \ No newline at end of file diff --git a/src/libs/LangChain.Core/Polyfills/HttpContext.ReadAsStringAsync.CancellationToken.cs b/src/libs/LangChain.Core/Polyfills/HttpContext.ReadAsStringAsync.CancellationToken.cs new file mode 100644 index 00000000..9e010a8b --- /dev/null +++ b/src/libs/LangChain.Core/Polyfills/HttpContext.ReadAsStringAsync.CancellationToken.cs @@ -0,0 +1,16 @@ +// ReSharper disable once CheckNamespace +namespace System.Net.Http; + +public static partial class HttpContextExtensions +{ +#if !NET6_0_OR_GREATER + public static async Task ReadAsStringAsync( + this HttpContent content, + CancellationToken cancellationToken = default) + { + content = content ?? throw new ArgumentNullException(nameof(content)); + + return await content.ReadAsStringAsync().ConfigureAwait(false); + } +#endif +} \ No newline at end of file diff --git a/src/tests/LangChain.Providers.Bedrock.IntegrationTests/BedrockTests.cs b/src/tests/LangChain.Providers.Bedrock.IntegrationTests/BedrockTests.cs index 3b37eb1a..67e43fcb 100644 --- a/src/tests/LangChain.Providers.Bedrock.IntegrationTests/BedrockTests.cs +++ b/src/tests/LangChain.Providers.Bedrock.IntegrationTests/BedrockTests.cs @@ -7,8 +7,8 @@ using LangChain.Indexes; using LangChain.Prompts; using LangChain.Providers.Amazon.Bedrock; -using LangChain.Providers.Amazon.Bedrock.Embeddings; -using LangChain.Providers.Amazon.Bedrock.Models; +using LangChain.Providers.Bedrock.Embeddings; +using LangChain.Providers.Bedrock.Models; using LangChain.Schema; using LangChain.Sources; using LangChain.TextSplitters; diff --git a/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Amazon.IntegrationTests.csproj b/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Amazon.IntegrationTests.csproj index 9bb95ca2..77f9c51f 100644 --- a/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Amazon.IntegrationTests.csproj +++ b/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Amazon.IntegrationTests.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Bedrock.IntegrationTests.csproj b/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Bedrock.IntegrationTests.csproj index 680cfe32..37a40063 100644 --- a/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Bedrock.IntegrationTests.csproj +++ b/src/tests/LangChain.Providers.Bedrock.IntegrationTests/LangChain.Providers.Bedrock.IntegrationTests.csproj @@ -10,7 +10,10 @@ + + +