Skip to content

Commit f02722d

Browse files
committed
refactor: fix anthropic endpoint & reasoning
1 parent e32930e commit f02722d

11 files changed

Lines changed: 103 additions & 2554 deletions

File tree

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,3 @@
1313
[submodule "3rd/semantic-kernel"]
1414
path = 3rd/semantic-kernel
1515
url = https://github.com/microsoft/semantic-kernel
16-
[submodule "3rd/anthropic-sdk-csharp"]
17-
path = 3rd/anthropic-sdk-csharp
18-
url = https://github.com/anthropics/anthropic-sdk-csharp

3rd/anthropic-sdk-csharp

Lines changed: 0 additions & 1 deletion
This file was deleted.

3rd/anthropic-sdk-csharp-patch/src/Anthropic/Anthropic.csproj

Lines changed: 0 additions & 1287 deletions
This file was deleted.

3rd/anthropic-sdk-csharp-patch/src/Anthropic/AnthropicClientExtensions.cs

Lines changed: 0 additions & 1119 deletions
This file was deleted.

3rd/anthropic-sdk-csharp-patch/src/Anthropic/Core/ModelBase.cs

Lines changed: 0 additions & 120 deletions
This file was deleted.

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
<PackageVersion Include="System.Text.Json" Version="$(MicrosoftPackageVersion)" />
5353
<PackageVersion Include="ZLinq" Version="1.5.4" />
5454
<!-- AI packages -->
55+
<PackageVersion Include="Anthropic" Version="12.8.0" />
5556
<PackageVersion Include="Microsoft.Extensions.AI" Version="$(MEAIVersion)" />
5657
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="$(MEAIVersion)" />
5758
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="$(MEAIVersion)-preview.1.26063.2" />

Everywhere.Windows.slnf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"solution": {
33
"path": "Everywhere.sln",
44
"projects": [
5-
"3rd\\anthropic-sdk-csharp-patch\\src\\Anthropic\\Anthropic.csproj",
65
"3rd\\EverythingNetCore\\EverythingNet\\EverythingNet.csproj",
76
"3rd\\MessagePack-CSharp\\src\\MessagePack.Analyzers.CodeFixes\\MessagePack.Analyzers.CodeFixes.csproj",
87
"3rd\\MessagePack-CSharp\\src\\MessagePack.Analyzers\\MessagePack.Analyzers.csproj",

Everywhere.sln

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Everywhere.Cloud", "src\Eve
121121
EndProject
122122
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Everywhere.Abstractions.Tests", "tests\Everywhere.Abstractions.Tests\Everywhere.Abstractions.Tests.csproj", "{9561A317-E9E5-4B18-9A3B-17D9BE54592A}"
123123
EndProject
124-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Anthropic", "3rd\anthropic-sdk-csharp-patch\src\Anthropic\Anthropic.csproj", "{C3305CE7-8C65-4856-A3BB-32C57BD607CD}"
125-
EndProject
126124
Global
127125
GlobalSection(SolutionConfigurationPlatforms) = preSolution
128126
Debug|Any CPU = Debug|Any CPU
@@ -229,10 +227,6 @@ Global
229227
{9561A317-E9E5-4B18-9A3B-17D9BE54592A}.Debug|Any CPU.Build.0 = Debug|Any CPU
230228
{9561A317-E9E5-4B18-9A3B-17D9BE54592A}.Release|Any CPU.ActiveCfg = Release|Any CPU
231229
{9561A317-E9E5-4B18-9A3B-17D9BE54592A}.Release|Any CPU.Build.0 = Release|Any CPU
232-
{C3305CE7-8C65-4856-A3BB-32C57BD607CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
233-
{C3305CE7-8C65-4856-A3BB-32C57BD607CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
234-
{C3305CE7-8C65-4856-A3BB-32C57BD607CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
235-
{C3305CE7-8C65-4856-A3BB-32C57BD607CD}.Release|Any CPU.Build.0 = Release|Any CPU
236230
EndGlobalSection
237231
GlobalSection(SolutionProperties) = preSolution
238232
HideSolutionNode = FALSE
@@ -256,7 +250,6 @@ Global
256250
{62900E41-0B12-4AD8-A71A-2D8C2C4D033A} = {1F3E1A58-51BB-46BD-815D-966D1BF0AB21}
257251
{521A03C8-BB0D-43AF-92DF-FAD510B91C24} = {1F3E1A58-51BB-46BD-815D-966D1BF0AB21}
258252
{9561A317-E9E5-4B18-9A3B-17D9BE54592A} = {9933B251-881A-4638-8995-EB7CC5370002}
259-
{C3305CE7-8C65-4856-A3BB-32C57BD607CD} = {53D93485-1520-4753-81CE-DA1CFF334372}
260253
EndGlobalSection
261254
GlobalSection(ExtensibilityGlobals) = postSolution
262255
SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E}

src/Everywhere.Abstractions/AI/ModelProviderSchema.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public string GetDefaultEndpoint()
2929
{
3030
ModelProviderSchema.OpenAI => "https://api.openai.com/v1",
3131
ModelProviderSchema.OpenAIResponses => "https://api.openai.com/v1",
32-
ModelProviderSchema.Anthropic => "https://api.anthropic.com/v1",
32+
ModelProviderSchema.Anthropic => "https://api.anthropic.com",
3333
ModelProviderSchema.Google => "https://generativelanguage.googleapis.com/v1beta",
3434
ModelProviderSchema.Ollama => "http://localhost:11434",
3535
ModelProviderSchema.DeepSeek => "https://api.deepseek.com/v1",
@@ -89,7 +89,7 @@ public string GetDefaultEndpoint()
8989
{
9090
ModelProviderSchema.OpenAI => $"{prefix}/v1",
9191
ModelProviderSchema.OpenAIResponses => $"{prefix}/v1",
92-
ModelProviderSchema.Anthropic => $"{prefix}/v1",
92+
ModelProviderSchema.Anthropic => prefix,
9393
ModelProviderSchema.Google => $"{prefix}/v1beta",
9494
ModelProviderSchema.Ollama => prefix,
9595
ModelProviderSchema.DeepSeek => $"{prefix}/v1",
@@ -112,7 +112,7 @@ public string PreviewEndpoint(string? endpoint)
112112
{
113113
ModelProviderSchema.OpenAI => $"{prefix}/chat/completions",
114114
ModelProviderSchema.OpenAIResponses => $"{prefix}/responses",
115-
ModelProviderSchema.Anthropic => $"{prefix}/messages",
115+
ModelProviderSchema.Anthropic => $"{prefix}/v1/messages",
116116
ModelProviderSchema.Google => $"{prefix}/models",
117117
ModelProviderSchema.Ollama => $"{prefix}/api/chat",
118118
ModelProviderSchema.DeepSeek => $"{prefix}/chat/completions",

src/Everywhere.Core/AI/AnthropicKernelMixin.cs

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Anthropic;
22
using Anthropic.Core;
3+
using Anthropic.Models.Messages;
34
using Microsoft.Extensions.AI;
45
using Microsoft.SemanticKernel.ChatCompletion;
56

@@ -19,13 +20,15 @@ public sealed class AnthropicKernelMixin : KernelMixinBase
1920
/// </summary>
2021
public AnthropicKernelMixin(CustomAssistant customAssistant, HttpClient httpClient) : base(customAssistant)
2122
{
22-
var anthropicClient = new AnthropicClient(new ClientOptions
23-
{
24-
ApiKey = ApiKey,
25-
HttpClient = httpClient,
26-
BaseUrl = Endpoint
27-
}).AsIChatClient(defaultModelId: ModelId);
28-
_client = new OptimizedChatClient(customAssistant, anthropicClient);
23+
var anthropicClient = new AnthropicClient(
24+
new ClientOptions
25+
{
26+
ApiKey = ApiKey,
27+
HttpClient = httpClient,
28+
BaseUrl = Endpoint,
29+
Timeout = TimeSpan.FromSeconds(customAssistant.RequestTimeoutSeconds)
30+
}).AsIChatClient();
31+
_client = new OptimizedChatClient(customAssistant, ModelId, anthropicClient);
2932
ChatCompletionService = _client.AsChatCompletionService();
3033
}
3134

@@ -34,17 +37,80 @@ public override void Dispose()
3437
_client.Dispose();
3538
}
3639

37-
private sealed class OptimizedChatClient(CustomAssistant customAssistant, IChatClient anthropicClient) : DelegatingChatClient(anthropicClient)
40+
private sealed class OptimizedChatClient(CustomAssistant customAssistant, string modelId, IChatClient anthropicClient)
41+
: DelegatingChatClient(anthropicClient)
3842
{
3943
private void BuildOptions(ref ChatOptions? options)
4044
{
41-
options ??= new ChatOptions();
45+
var chatOptions = options ??= new ChatOptions();
4246

4347
double? temperature = customAssistant.Temperature.IsCustomValueSet ? customAssistant.Temperature.ActualValue : null;
4448
double? topP = customAssistant.TopP.IsCustomValueSet ? customAssistant.TopP.ActualValue : null;
4549

4650
if (temperature is not null) options.Temperature = (float)temperature.Value;
4751
if (topP is not null) options.TopP = (float)topP.Value;
52+
53+
options.RawRepresentationFactory = OptionsRawRepresentationFactory;
54+
55+
object? OptionsRawRepresentationFactory(IChatClient _)
56+
{
57+
// TODO: fuck these shits
58+
var maxTokens = modelId switch
59+
{
60+
_ when modelId.StartsWith("claude-3-haiku") => 4096,
61+
_ when modelId.StartsWith("claude-3-5-haiku") => 8192,
62+
_ when modelId.StartsWith("claude-opus-4") => 32000,
63+
_ when modelId.StartsWith("claude-opus-4-1") => 32000,
64+
_ when modelId.StartsWith("claude-opus-4-6") => 128000,
65+
_ => 64000,
66+
};
67+
68+
ThinkingConfigParam thinking;
69+
if (customAssistant.IsDeepThinkingSupported)
70+
{
71+
int budgetTokens;
72+
if (chatOptions.AdditionalProperties?.TryGetValue("reasoning_effort_level", out var reasoningEffortLevelObj) is not true ||
73+
reasoningEffortLevelObj is not ReasoningEffortLevel reasoningEffortLevel)
74+
{
75+
budgetTokens = -1;
76+
}
77+
else
78+
{
79+
budgetTokens = reasoningEffortLevel switch
80+
{
81+
ReasoningEffortLevel.Detailed => Math.Min(maxTokens / 2, 4096),
82+
ReasoningEffortLevel.Minimal => 1024,
83+
_ => -1
84+
};
85+
}
86+
87+
if (budgetTokens == -1 && modelId.StartsWith("claude-opus-4-6"))
88+
{
89+
thinking = new ThinkingConfigParam(new ThinkingConfigAdaptive());
90+
}
91+
else
92+
{
93+
thinking = new ThinkingConfigParam(
94+
new ThinkingConfigEnabled
95+
{
96+
BudgetTokens = Math.Max(budgetTokens, 2048)
97+
});
98+
}
99+
}
100+
else
101+
{
102+
thinking = new ThinkingConfigParam(new ThinkingConfigDisabled());
103+
}
104+
105+
return new MessageCreateParams
106+
{
107+
MaxTokens = maxTokens,
108+
Messages = [], // Leave empty and underlying implementation will handle it
109+
Model = modelId,
110+
Thinking = thinking,
111+
CacheControl = new CacheControlEphemeral()
112+
};
113+
}
48114
}
49115

50116
public override Task<ChatResponse> GetResponseAsync(
@@ -56,13 +122,33 @@ public override Task<ChatResponse> GetResponseAsync(
56122
return base.GetResponseAsync(messages, options, cancellationToken);
57123
}
58124

59-
public override IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
125+
public override async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
60126
IEnumerable<ChatMessage> messages,
61127
ChatOptions? options = null,
62-
CancellationToken cancellationToken = default)
128+
[EnumeratorCancellation] CancellationToken cancellationToken = default)
63129
{
64130
BuildOptions(ref options);
65-
return base.GetStreamingResponseAsync(messages, options, cancellationToken);
131+
132+
// Extract reasoning contents since SK didn't convert them from MEAI
133+
await foreach (var update in base.GetStreamingResponseAsync(messages, options, cancellationToken))
134+
{
135+
for (var i = 0; i < update.Contents.Count; i++)
136+
{
137+
if (update.Contents[i] is TextReasoningContent textReasoningContent)
138+
{
139+
update.Contents[i] = new TextContent(textReasoningContent.Text)
140+
{
141+
// This line actually takes no effect because
142+
// Microsoft.Extensions.AI.ChatResponseUpdateExtensions.ToStreamingChatMessageContent
143+
// forget to include item's AdditionalProperties in Metadata
144+
AdditionalProperties = ReasoningProperties
145+
};
146+
update.AdditionalProperties = ApplyReasoningProperties(update.AdditionalProperties);
147+
}
148+
}
149+
150+
yield return update;
151+
}
66152
}
67153
}
68154
}

0 commit comments

Comments
 (0)