diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index be40e7b61b6d..af136757410a 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -38,6 +38,9 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.OpenAI.Tests", "test\AutoGen.OpenAI.Tests\AutoGen.OpenAI.Tests.csproj", "{D36A85F9-C172-487D-8192-6BFE5D05B4A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.DotnetInteractive.Tests", "test\AutoGen.DotnetInteractive.Tests\AutoGen.DotnetInteractive.Tests.csproj", "{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.OpenAI.Tests", "test\AutoGen.OpenAI.Tests\AutoGen.OpenAI.Tests.csproj", "{D36A85F9-C172-487D-8192-6BFE5D05B4A7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.DotnetInteractive.Tests", "test\AutoGen.DotnetInteractive.Tests\AutoGen.DotnetInteractive.Tests.csproj", "{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.Ollama", "src\AutoGen.Ollama\AutoGen.Ollama.csproj", "{9F9E6DED-3D92-4970-909A-70FC11F1A665}"
EndProject
@@ -46,6 +49,12 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.Ollama.Sample", "sample\AutoGen.Ollama.Sample\AutoGen.Ollama.Sample.csproj", "{93AA4D0D-6EE4-44D5-AD77-7F73A3934544}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.SemanticKernel.Sample", "sample\AutoGen.SemanticKernel.Sample\AutoGen.SemanticKernel.Sample.csproj", "{52958A60-3FF7-4243-9058-34A6E4F55C31}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.Anthropic", "src\AutoGen.Anthropic\AutoGen.Anthropic.csproj", "{6A95E113-B824-4524-8F13-CD0C3E1C8804}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.Anthropic.Tests", "test\AutoGen.Anthropic.Tests\AutoGen.Anthropic.Tests.csproj", "{815E937E-86D6-4476-9EC6-B7FBCBBB5DB6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.Anthropic.Samples", "sample\AutoGen.Anthropic.Samples\AutoGen.Anthropic.Samples.csproj", "{834B4E85-64E5-4382-8465-548F332E5298}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -128,6 +137,18 @@ Global
{52958A60-3FF7-4243-9058-34A6E4F55C31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{52958A60-3FF7-4243-9058-34A6E4F55C31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{52958A60-3FF7-4243-9058-34A6E4F55C31}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6A95E113-B824-4524-8F13-CD0C3E1C8804}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6A95E113-B824-4524-8F13-CD0C3E1C8804}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6A95E113-B824-4524-8F13-CD0C3E1C8804}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6A95E113-B824-4524-8F13-CD0C3E1C8804}.Release|Any CPU.Build.0 = Release|Any CPU
+ {815E937E-86D6-4476-9EC6-B7FBCBBB5DB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {815E937E-86D6-4476-9EC6-B7FBCBBB5DB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {815E937E-86D6-4476-9EC6-B7FBCBBB5DB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {815E937E-86D6-4476-9EC6-B7FBCBBB5DB6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {834B4E85-64E5-4382-8465-548F332E5298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {834B4E85-64E5-4382-8465-548F332E5298}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {834B4E85-64E5-4382-8465-548F332E5298}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {834B4E85-64E5-4382-8465-548F332E5298}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -148,6 +169,9 @@ Global
{1DFABC4A-8458-4875-8DCB-59F3802DAC65} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
{D36A85F9-C172-487D-8192-6BFE5D05B4A7} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+ {6A95E113-B824-4524-8F13-CD0C3E1C8804} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
+ {815E937E-86D6-4476-9EC6-B7FBCBBB5DB6} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+ {834B4E85-64E5-4382-8465-548F332E5298} = {FBFEAD1F-29EB-4D99-A672-0CD8473E10B9}
{9F9E6DED-3D92-4970-909A-70FC11F1A665} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
{03E31CAA-3728-48D3-B936-9F11CF6C18FE} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
{93AA4D0D-6EE4-44D5-AD77-7F73A3934544} = {FBFEAD1F-29EB-4D99-A672-0CD8473E10B9}
diff --git a/dotnet/sample/AutoGen.Anthropic.Samples/AnthropicSamples.cs b/dotnet/sample/AutoGen.Anthropic.Samples/AnthropicSamples.cs
new file mode 100644
index 000000000000..94b5f37511e6
--- /dev/null
+++ b/dotnet/sample/AutoGen.Anthropic.Samples/AnthropicSamples.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AnthropicSamples.cs
+
+using AutoGen.Anthropic.Extensions;
+using AutoGen.Anthropic.Utils;
+using AutoGen.Core;
+
+namespace AutoGen.Anthropic.Samples;
+
+public static class AnthropicSamples
+{
+ public static async Task RunAsync()
+ {
+ #region create_anthropic_agent
+ var apiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY") ?? throw new Exception("Missing ANTHROPIC_API_KEY environment variable.");
+ var anthropicClient = new AnthropicClient(new HttpClient(), AnthropicConstants.Endpoint, apiKey);
+ var agent = new AnthropicClientAgent(anthropicClient, "assistant", AnthropicConstants.Claude3Haiku);
+ #endregion
+
+ #region register_middleware
+ var agentWithConnector = agent
+ .RegisterMessageConnector()
+ .RegisterPrintMessage();
+ #endregion register_middleware
+
+ await agentWithConnector.SendAsync(new TextMessage(Role.Assistant, "Hello", from: "user"));
+ }
+}
diff --git a/dotnet/sample/AutoGen.Anthropic.Samples/AutoGen.Anthropic.Samples.csproj b/dotnet/sample/AutoGen.Anthropic.Samples/AutoGen.Anthropic.Samples.csproj
new file mode 100644
index 000000000000..33a5aa7f16b6
--- /dev/null
+++ b/dotnet/sample/AutoGen.Anthropic.Samples/AutoGen.Anthropic.Samples.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ $(TestTargetFramework)
+ enable
+ enable
+ True
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/sample/AutoGen.Anthropic.Samples/Program.cs b/dotnet/sample/AutoGen.Anthropic.Samples/Program.cs
new file mode 100644
index 000000000000..f3c615088610
--- /dev/null
+++ b/dotnet/sample/AutoGen.Anthropic.Samples/Program.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Program.cs
+
+namespace AutoGen.Anthropic.Samples;
+
+internal static class Program
+{
+ public static async Task Main(string[] args)
+ {
+ await AnthropicSamples.RunAsync();
+ }
+}
diff --git a/dotnet/src/AutoGen.Anthropic/Agent/AnthropicClientAgent.cs b/dotnet/src/AutoGen.Anthropic/Agent/AnthropicClientAgent.cs
new file mode 100644
index 000000000000..e395bb4a225f
--- /dev/null
+++ b/dotnet/src/AutoGen.Anthropic/Agent/AnthropicClientAgent.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using AutoGen.Anthropic.DTO;
+using AutoGen.Core;
+
+namespace AutoGen.Anthropic;
+
+public class AnthropicClientAgent : IStreamingAgent
+{
+ private readonly AnthropicClient _anthropicClient;
+ public string Name { get; }
+ private readonly string _modelName;
+ private readonly string _systemMessage;
+ private readonly decimal _temperature;
+ private readonly int _maxTokens;
+
+ public AnthropicClientAgent(
+ AnthropicClient anthropicClient,
+ string name,
+ string modelName,
+ string systemMessage = "You are a helpful AI assistant",
+ decimal temperature = 0.7m,
+ int maxTokens = 1024)
+ {
+ Name = name;
+ _anthropicClient = anthropicClient;
+ _modelName = modelName;
+ _systemMessage = systemMessage;
+ _temperature = temperature;
+ _maxTokens = maxTokens;
+ }
+
+ public async Task GenerateReplyAsync(IEnumerable messages, GenerateReplyOptions? options = null,
+ CancellationToken cancellationToken = default)
+ {
+ var response = await _anthropicClient.CreateChatCompletionsAsync(CreateParameters(messages, options, false), cancellationToken);
+ return new MessageEnvelope(response, from: this.Name);
+ }
+
+ public async IAsyncEnumerable GenerateStreamingReplyAsync(IEnumerable messages,
+ GenerateReplyOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
+ {
+ await foreach (var message in _anthropicClient.StreamingChatCompletionsAsync(
+ CreateParameters(messages, options, true), cancellationToken))
+ {
+ yield return new MessageEnvelope(message, from: this.Name);
+ }
+ }
+
+ private ChatCompletionRequest CreateParameters(IEnumerable messages, GenerateReplyOptions? options, bool shouldStream)
+ {
+ var chatCompletionRequest = new ChatCompletionRequest()
+ {
+ SystemMessage = _systemMessage,
+ MaxTokens = options?.MaxToken ?? _maxTokens,
+ Model = _modelName,
+ Stream = shouldStream,
+ Temperature = (decimal?)options?.Temperature ?? _temperature,
+ };
+
+ chatCompletionRequest.Messages = BuildMessages(messages);
+
+ return chatCompletionRequest;
+ }
+
+ private List BuildMessages(IEnumerable messages)
+ {
+ List chatMessages = new();
+ foreach (IMessage? message in messages)
+ {
+ switch (message)
+ {
+ case IMessage chatMessage when chatMessage.Content.Role == "system":
+ throw new InvalidOperationException(
+ "system message has already been set and only one system message is supported. \"system\" role for input messages in the Message");
+
+ case IMessage chatMessage:
+ chatMessages.Add(chatMessage.Content);
+ break;
+
+ default:
+ throw new ArgumentException($"Unexpected message type: {message?.GetType()}");
+ }
+ }
+
+ return chatMessages;
+ }
+}
diff --git a/dotnet/src/AutoGen.Anthropic/AnthropicClient.cs b/dotnet/src/AutoGen.Anthropic/AnthropicClient.cs
new file mode 100644
index 000000000000..8ea0bef86e2c
--- /dev/null
+++ b/dotnet/src/AutoGen.Anthropic/AnthropicClient.cs
@@ -0,0 +1,122 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AnthropicClient.cs
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Http;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using AutoGen.Anthropic.Converters;
+using AutoGen.Anthropic.DTO;
+
+namespace AutoGen.Anthropic;
+
+public sealed class AnthropicClient : IDisposable
+{
+ private readonly HttpClient _httpClient;
+ private readonly string _baseUrl;
+
+ private static readonly JsonSerializerOptions JsonSerializerOptions = new()
+ {
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
+ };
+
+ private static readonly JsonSerializerOptions JsonDeserializerOptions = new()
+ {
+ Converters = { new ContentBaseConverter() }
+ };
+
+ public AnthropicClient(HttpClient httpClient, string baseUrl, string apiKey)
+ {
+ _httpClient = httpClient;
+ _baseUrl = baseUrl;
+
+ _httpClient.DefaultRequestHeaders.Add("x-api-key", apiKey);
+ _httpClient.DefaultRequestHeaders.Add("anthropic-version", "2023-06-01");
+ }
+
+ public async Task CreateChatCompletionsAsync(ChatCompletionRequest chatCompletionRequest,
+ CancellationToken cancellationToken)
+ {
+ var httpResponseMessage = await SendRequestAsync(chatCompletionRequest, cancellationToken);
+ var responseStream = await httpResponseMessage.Content.ReadAsStreamAsync();
+
+ if (httpResponseMessage.IsSuccessStatusCode)
+ return await DeserializeResponseAsync(responseStream, cancellationToken);
+
+ ErrorResponse res = await DeserializeResponseAsync(responseStream, cancellationToken);
+ throw new Exception(res.Error?.Message);
+ }
+
+ public async IAsyncEnumerable StreamingChatCompletionsAsync(
+ ChatCompletionRequest chatCompletionRequest, [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ var httpResponseMessage = await SendRequestAsync(chatCompletionRequest, cancellationToken);
+ using var reader = new StreamReader(await httpResponseMessage.Content.ReadAsStreamAsync());
+
+ var currentEvent = new SseEvent();
+ while (await reader.ReadLineAsync() is { } line)
+ {
+ if (!string.IsNullOrEmpty(line))
+ {
+ currentEvent.Data = line.Substring("data:".Length).Trim();
+ }
+ else
+ {
+ if (currentEvent.Data == "[DONE]")
+ continue;
+
+ if (currentEvent.Data != null)
+ {
+ yield return await JsonSerializer.DeserializeAsync(
+ new MemoryStream(Encoding.UTF8.GetBytes(currentEvent.Data)),
+ cancellationToken: cancellationToken) ?? throw new Exception("Failed to deserialize response");
+ }
+ else if (currentEvent.Data != null)
+ {
+ var res = await JsonSerializer.DeserializeAsync(
+ new MemoryStream(Encoding.UTF8.GetBytes(currentEvent.Data)), cancellationToken: cancellationToken);
+
+ throw new Exception(res?.Error?.Message);
+ }
+
+ // Reset the current event for the next one
+ currentEvent = new SseEvent();
+ }
+ }
+ }
+
+ private Task SendRequestAsync(T requestObject, CancellationToken cancellationToken)
+ {
+ var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, _baseUrl);
+ var jsonRequest = JsonSerializer.Serialize(requestObject, JsonSerializerOptions);
+ httpRequestMessage.Content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
+ return _httpClient.SendAsync(httpRequestMessage, cancellationToken);
+ }
+
+ private async Task DeserializeResponseAsync(Stream responseStream, CancellationToken cancellationToken)
+ {
+ return await JsonSerializer.DeserializeAsync(responseStream, JsonDeserializerOptions, cancellationToken)
+ ?? throw new Exception("Failed to deserialize response");
+ }
+
+ public void Dispose()
+ {
+ _httpClient.Dispose();
+ }
+
+ private struct SseEvent
+ {
+ public string? Data { get; set; }
+
+ public SseEvent(string? data = null)
+ {
+ Data = data;
+ }
+ }
+}
diff --git a/dotnet/src/AutoGen.Anthropic/AutoGen.Anthropic.csproj b/dotnet/src/AutoGen.Anthropic/AutoGen.Anthropic.csproj
new file mode 100644
index 000000000000..fefc439e00ba
--- /dev/null
+++ b/dotnet/src/AutoGen.Anthropic/AutoGen.Anthropic.csproj
@@ -0,0 +1,22 @@
+
+
+
+ netstandard2.0
+ AutoGen.Anthropic
+
+
+
+
+
+
+ AutoGen.Anthropic
+
+ Provide support for consuming Anthropic models in AutoGen
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/AutoGen.Anthropic/Converters/ContentBaseConverter.cs b/dotnet/src/AutoGen.Anthropic/Converters/ContentBaseConverter.cs
new file mode 100644
index 000000000000..281274048eda
--- /dev/null
+++ b/dotnet/src/AutoGen.Anthropic/Converters/ContentBaseConverter.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// ContentConverter.cs
+
+using AutoGen.Anthropic.DTO;
+
+namespace AutoGen.Anthropic.Converters;
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+public sealed class ContentBaseConverter : JsonConverter
+{
+ public override ContentBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ using var doc = JsonDocument.ParseValue(ref reader);
+ if (doc.RootElement.TryGetProperty("type", out JsonElement typeProperty) && !string.IsNullOrEmpty(typeProperty.GetString()))
+ {
+ string? type = typeProperty.GetString();
+ var text = doc.RootElement.GetRawText();
+ switch (type)
+ {
+ case "text":
+ return JsonSerializer.Deserialize(text, options) ?? throw new InvalidOperationException();
+ case "image":
+ return JsonSerializer.Deserialize(text, options) ?? throw new InvalidOperationException();
+ }
+ }
+
+ throw new JsonException("Unknown content type");
+ }
+
+ public override void Write(Utf8JsonWriter writer, ContentBase value, JsonSerializerOptions options)
+ {
+ JsonSerializer.Serialize(writer, value, value.GetType(), options);
+ }
+}
diff --git a/dotnet/src/AutoGen.Anthropic/DTO/ChatCompletionRequest.cs b/dotnet/src/AutoGen.Anthropic/DTO/ChatCompletionRequest.cs
new file mode 100644
index 000000000000..fa1654bc11d0
--- /dev/null
+++ b/dotnet/src/AutoGen.Anthropic/DTO/ChatCompletionRequest.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+using System.Text.Json.Serialization;
+
+namespace AutoGen.Anthropic.DTO;
+
+using System.Collections.Generic;
+
+public class ChatCompletionRequest
+{
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
+ [JsonPropertyName("messages")]
+ public List Messages { get; set; }
+
+ [JsonPropertyName("system")]
+ public string? SystemMessage { get; set; }
+
+ [JsonPropertyName("max_tokens")]
+ public int MaxTokens { get; set; }
+
+ [JsonPropertyName("metadata")]
+ public object? Metadata { get; set; }
+
+ [JsonPropertyName("stop_sequences")]
+ public string[]? StopSequences { get; set; }
+
+ [JsonPropertyName("stream")]
+ public bool? Stream { get; set; }
+
+ [JsonPropertyName("temperature")]
+ public decimal? Temperature { get; set; }
+
+ [JsonPropertyName("top_k")]
+ public int? TopK { get; set; }
+
+ [JsonPropertyName("top_p")]
+ public decimal? TopP { get; set; }
+
+ public ChatCompletionRequest()
+ {
+ Messages = new List();
+ }
+}
+
+public class ChatMessage
+{
+ [JsonPropertyName("role")]
+ public string Role { get; set; }
+
+ [JsonPropertyName("content")]
+ public string Content { get; set; }
+
+ public ChatMessage(string role, string content)
+ {
+ Role = role;
+ Content = content;
+ }
+}
diff --git a/dotnet/src/AutoGen.Anthropic/DTO/ChatCompletionResponse.cs b/dotnet/src/AutoGen.Anthropic/DTO/ChatCompletionResponse.cs
new file mode 100644
index 000000000000..c6861f9c3150
--- /dev/null
+++ b/dotnet/src/AutoGen.Anthropic/DTO/ChatCompletionResponse.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+namespace AutoGen.Anthropic.DTO;
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+public class ChatCompletionResponse
+{
+ [JsonPropertyName("content")]
+ public List? Content { get; set; }
+
+ [JsonPropertyName("id")]
+ public string? Id { get; set; }
+
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
+ [JsonPropertyName("role")]
+ public string? Role { get; set; }
+
+ [JsonPropertyName("stop_reason")]
+ public string? StopReason { get; set; }
+
+ [JsonPropertyName("stop_sequence")]
+ public object? StopSequence { get; set; }
+
+ [JsonPropertyName("type")]
+ public string? Type { get; set; }
+
+ [JsonPropertyName("usage")]
+ public Usage? Usage { get; set; }
+
+ [JsonPropertyName("delta")]
+ public Delta? Delta { get; set; }
+
+ [JsonPropertyName("message")]
+ public StreamingMessage? streamingMessage { get; set; }
+}
+
+public class StreamingMessage
+{
+ [JsonPropertyName("id")]
+ public string? Id { get; set; }
+
+ [JsonPropertyName("type")]
+ public string? Type { get; set; }
+
+ [JsonPropertyName("role")]
+ public string? Role { get; set; }
+
+ [JsonPropertyName("content")]
+ public List