Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions Anthropic.SDK.Tests/Anthropic.SDK.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Google.Cloud.AIPlatform.V1" Version="3.60.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.AI" Version="10.2.0" />
<PackageReference Include="ModelContextProtocol" Version="0.6.0-preview.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.2" />
<PackageReference Include="Google.Cloud.AIPlatform.V1" Version="3.65.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="11.0.0-preview.1.26104.118" />
<PackageReference Include="Microsoft.Extensions.AI" Version="10.3.0" />
<PackageReference Include="ModelContextProtocol" Version="0.8.0-preview.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="11.0.0-preview.1.26104.118" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="11.0.0-preview.1.26104.118" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="11.0.0-preview.1.26104.118" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.69.0" />
<PackageReference Include="Microsoft.SemanticKernel.Abstractions" Version="1.69.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="4.0.2" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.71.0" />
<PackageReference Include="Microsoft.SemanticKernel.Abstractions" Version="1.71.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>

Expand Down
252 changes: 248 additions & 4 deletions Anthropic.SDK.Tests/ChatOptionsExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void WithThinking_SetsThinkingParameters()
var thinkingParams = options.GetThinkingParameters();
Assert.IsNotNull(thinkingParams);
Assert.AreEqual(budgetTokens, thinkingParams.BudgetTokens);
Assert.AreEqual("enabled", thinkingParams.Type);
Assert.AreEqual(ThinkingType.enabled, thinkingParams.Type);
Assert.IsFalse(thinkingParams.UseInterleavedThinking);
}

Expand Down Expand Up @@ -63,7 +63,7 @@ public void WithInterleavedThinking_SetsInterleavedThinkingParameters()
var thinkingParams = options.GetThinkingParameters();
Assert.IsNotNull(thinkingParams);
Assert.AreEqual(budgetTokens, thinkingParams.BudgetTokens);
Assert.AreEqual("enabled", thinkingParams.Type);
Assert.AreEqual(ThinkingType.enabled, thinkingParams.Type);
Assert.IsTrue(thinkingParams.UseInterleavedThinking);
}

Expand Down Expand Up @@ -291,7 +291,7 @@ public void ChatClientHelper_MapsThinkingParametersCorrectly()
// Assert
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(3000, messageParams.Thinking.BudgetTokens);
Assert.AreEqual("enabled", messageParams.Thinking.Type);
Assert.AreEqual(ThinkingType.enabled, messageParams.Thinking.Type);
Assert.IsFalse(messageParams.Thinking.UseInterleavedThinking);
Assert.AreEqual(AnthropicModels.Claude37Sonnet, messageParams.Model);
Assert.AreEqual(4096, messageParams.MaxTokens);
Expand Down Expand Up @@ -319,10 +319,254 @@ public void ChatClientHelper_MapsInterleavedThinkingParametersCorrectly()
// Assert
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(8000, messageParams.Thinking.BudgetTokens);
Assert.AreEqual("enabled", messageParams.Thinking.Type);
Assert.AreEqual(ThinkingType.enabled, messageParams.Thinking.Type);
Assert.IsTrue(messageParams.Thinking.UseInterleavedThinking);
Assert.AreEqual(AnthropicModels.Claude37Sonnet, messageParams.Model);
Assert.AreEqual(4096, messageParams.MaxTokens);
}

[TestMethod]
public void WithAdaptiveThinking_SetsAdaptiveType()
{
// Arrange
var options = new ChatOptions();

// Act
var result = options.WithAdaptiveThinking();

// Assert
Assert.AreSame(options, result);
var thinkingParams = options.GetThinkingParameters();
Assert.IsNotNull(thinkingParams);
Assert.AreEqual(ThinkingType.adaptive, thinkingParams.Type);
Assert.IsNull(thinkingParams.BudgetTokens);
Assert.IsNull(thinkingParams.Effort);
}

[TestMethod]
public void WithAdaptiveThinking_WithEffort_SetsEffortAndAdaptiveType()
{
// Arrange
var options = new ChatOptions();

// Act
var result = options.WithAdaptiveThinking(ThinkingEffort.medium);

// Assert
Assert.AreSame(options, result);
var thinkingParams = options.GetThinkingParameters();
Assert.IsNotNull(thinkingParams);
Assert.AreEqual(ThinkingType.adaptive, thinkingParams.Type);
Assert.AreEqual(ThinkingEffort.medium, thinkingParams.Effort);
Assert.IsNull(thinkingParams.BudgetTokens);
}

[TestMethod]
public void WithAdaptiveThinking_NullOptions_ThrowsArgumentNullException()
{
// Arrange
ChatOptions options = null;

// Act & Assert
Assert.Throws<ArgumentNullException>(() => options.WithAdaptiveThinking());
Assert.Throws<ArgumentNullException>(() => options.WithAdaptiveThinking(ThinkingEffort.high));
}

[TestMethod]
public void WithAdaptiveThinking_FluentChaining_Works()
{
// Arrange & Act
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
Temperature = 1.0f
}.WithAdaptiveThinking(ThinkingEffort.high);

// Assert
Assert.AreEqual(AnthropicModels.Claude46Sonnet, options.ModelId);
Assert.AreEqual(16000, options.MaxOutputTokens);
Assert.AreEqual(1.0f, options.Temperature);

var thinkingParams = options.GetThinkingParameters();
Assert.IsNotNull(thinkingParams);
Assert.AreEqual(ThinkingType.adaptive, thinkingParams.Type);
Assert.AreEqual(ThinkingEffort.high, thinkingParams.Effort);
}

[TestMethod]
public void WithAdaptiveThinking_OverwritesPreviousThinkingParameters()
{
// Arrange
var options = new ChatOptions();
options.WithThinking(3000);

// Act
options.WithAdaptiveThinking(ThinkingEffort.medium);

// Assert
var thinkingParams = options.GetThinkingParameters();
Assert.IsNotNull(thinkingParams);
Assert.AreEqual(ThinkingType.adaptive, thinkingParams.Type);
Assert.AreEqual(ThinkingEffort.medium, thinkingParams.Effort);
Assert.IsNull(thinkingParams.BudgetTokens);
}

[TestMethod]
public void ChatClientHelper_MapsAdaptiveThinkingCorrectly()
{
// Arrange
var client = new AnthropicClient().Messages;
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Test message")
};
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
}.WithAdaptiveThinking(ThinkingEffort.medium);

// Act
var messageParams = ChatClientHelper.CreateMessageParameters(client, messages, options);

// Assert
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(ThinkingType.adaptive, messageParams.Thinking.Type);
Assert.IsNull(messageParams.Thinking.BudgetTokens);
Assert.IsNotNull(messageParams.OutputConfig);
Assert.AreEqual(ThinkingEffort.medium, messageParams.OutputConfig.Effort);
}

[TestMethod]
public void ChatClientHelper_MapsAdaptiveThinkingWithoutEffort()
{
// Arrange
var client = new AnthropicClient().Messages;
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Test message")
};
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
}.WithAdaptiveThinking();

// Act
var messageParams = ChatClientHelper.CreateMessageParameters(client, messages, options);

// Assert
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(ThinkingType.adaptive, messageParams.Thinking.Type);
Assert.IsNull(messageParams.Thinking.BudgetTokens);
Assert.IsNull(messageParams.OutputConfig);
}

[TestMethod]
public void ChatClientHelper_MapsReasoningOptionsToAdaptiveThinking()
{
// Arrange
var client = new AnthropicClient().Messages;
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Test message")
};
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
Reasoning = new ReasoningOptions { Effort = ReasoningEffort.Medium }
};

// Act
var messageParams = ChatClientHelper.CreateMessageParameters(client, messages, options);

// Assert
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(ThinkingType.adaptive, messageParams.Thinking.Type);
Assert.IsNull(messageParams.Thinking.BudgetTokens);
Assert.IsNotNull(messageParams.OutputConfig);
Assert.AreEqual(ThinkingEffort.medium, messageParams.OutputConfig.Effort);
}

[TestMethod]
[DataRow(ReasoningEffort.Low, ThinkingEffort.low)]
[DataRow(ReasoningEffort.Medium, ThinkingEffort.medium)]
[DataRow(ReasoningEffort.High, ThinkingEffort.high)]
[DataRow(ReasoningEffort.ExtraHigh, ThinkingEffort.max)]
public void ChatClientHelper_MapsAllReasoningEffortLevels(ReasoningEffort reasoningEffort, ThinkingEffort expectedEffort)
{
// Arrange
var client = new AnthropicClient().Messages;
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Test message")
};
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
Reasoning = new ReasoningOptions { Effort = reasoningEffort }
};

// Act
var messageParams = ChatClientHelper.CreateMessageParameters(client, messages, options);

// Assert
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(ThinkingType.adaptive, messageParams.Thinking.Type);
Assert.IsNotNull(messageParams.OutputConfig);
Assert.AreEqual(expectedEffort, messageParams.OutputConfig.Effort);
}

[TestMethod]
public void ChatClientHelper_ReasoningOptionsNone_ClearsThinking()
{
// Arrange
var client = new AnthropicClient().Messages;
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Test message")
};
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
Reasoning = new ReasoningOptions { Effort = ReasoningEffort.None }
};

// Act
var messageParams = ChatClientHelper.CreateMessageParameters(client, messages, options);

// Assert
Assert.IsNull(messageParams.Thinking);
}

[TestMethod]
public void ChatClientHelper_ExplicitThinkingTakesPrecedenceOverReasoningOptions()
{
// Arrange
var client = new AnthropicClient().Messages;
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Test message")
};
var options = new ChatOptions
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 16000,
Reasoning = new ReasoningOptions { Effort = ReasoningEffort.Low }
}.WithAdaptiveThinking(ThinkingEffort.max);

// Act
var messageParams = ChatClientHelper.CreateMessageParameters(client, messages, options);

// Assert - WithAdaptiveThinking should win over ReasoningOptions
Assert.IsNotNull(messageParams.Thinking);
Assert.AreEqual(ThinkingType.adaptive, messageParams.Thinking.Type);
Assert.IsNotNull(messageParams.OutputConfig);
Assert.AreEqual(ThinkingEffort.max, messageParams.OutputConfig.Effort);
}
}
}
50 changes: 50 additions & 0 deletions Anthropic.SDK.Tests/Messages.ChatClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,56 @@ public async Task TestNonStreamingThinkingWithExtensionMethods()
Assert.IsTrue(res.Text?.Contains("10") is true, res.Text);
}

[TestMethod]
public async Task TestNonStreamingThinkingAdaptiveWithExtensionMethods()
{
IChatClient client = new AnthropicClient().Messages;

List<ChatMessage> messages = new()
{
new ChatMessage(ChatRole.User, "How many r's are in the word strawberry?")
};

ChatOptions options = new ChatOptions()
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 20000,
Temperature = 1.0f,
}.WithAdaptiveThinking(ThinkingEffort.high);

var res = await client.GetResponseAsync(messages, options);
Assert.IsTrue(res.Text.Contains("3") is true, res.Text);
messages.AddMessages(res);
messages.Add(new ChatMessage(ChatRole.User, "and how many letters total?"));
res = await client.GetResponseAsync(messages, options);
Assert.IsTrue(res.Text?.Contains("10") is true, res.Text);
}

[TestMethod]
public async Task TestNonStreamingThinkingAdaptive()
{
IChatClient client = new AnthropicClient().Messages;

List<ChatMessage> messages = new()
{
new ChatMessage(ChatRole.User, "How many r's are in the word strawberry?")
};

ChatOptions options = new ChatOptions()
{
ModelId = AnthropicModels.Claude46Sonnet,
MaxOutputTokens = 20000,
Temperature = 1.0f,
Reasoning = new ReasoningOptions()
{
Effort = ReasoningEffort.High,
}
};

var res = await client.GetResponseAsync(messages, options);
Assert.IsTrue(res.Text.Contains("3") is true, res.Text);
}

[TestMethod]
public async Task TestThinkingStreamingWithExtensionMethods()
{
Expand Down
Loading
Loading