Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ internal async Task NotifyProvidersOfFailureAsync(
requestChatOptions.ModelId ??= this._agentOptions.ChatOptions.ModelId;
requestChatOptions.PresencePenalty ??= this._agentOptions.ChatOptions.PresencePenalty;
requestChatOptions.ResponseFormat ??= this._agentOptions.ChatOptions.ResponseFormat;
requestChatOptions.Reasoning ??= this._agentOptions.ChatOptions.Reasoning;
requestChatOptions.Seed ??= this._agentOptions.ChatOptions.Seed;
requestChatOptions.Temperature ??= this._agentOptions.ChatOptions.Temperature;
requestChatOptions.TopP ??= this._agentOptions.ChatOptions.TopP;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,115 @@ public async Task ChatOptionsMergingUsesRawRepresentationFactoryWithFallbackAsyn
Assert.Equal(expectedSetting, capturedChatOptions.RawRepresentationFactory(null!));
}

/// <summary>
/// Verify that <see cref="ChatOptions.Reasoning"/> from the request takes priority over the agent's.
/// </summary>
[Fact]
public async Task ChatOptionsMergingUsesRequestReasoningOverAgentReasoningAsync()
{
// Arrange
var agentReasoning = new ReasoningOptions { Effort = ReasoningEffort.Low, Output = ReasoningOutput.Full };
var requestReasoning = new ReasoningOptions { Effort = ReasoningEffort.High, Output = ReasoningOutput.Full };

Mock<IChatClient> mockService = new();
ChatOptions? capturedChatOptions = null;
mockService.Setup(
s => s.GetResponseAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<ChatOptions>(),
It.IsAny<CancellationToken>()))
.Callback<IEnumerable<ChatMessage>, ChatOptions, CancellationToken>((msgs, opts, ct) =>
capturedChatOptions = opts)
.ReturnsAsync(new ChatResponse([new(ChatRole.Assistant, "response")]));

ChatClientAgent agent = new(mockService.Object, options: new()
{
ChatOptions = new ChatOptions { Reasoning = agentReasoning }
});
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };

// Act
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(new ChatOptions { Reasoning = requestReasoning }));

// Assert
Assert.NotNull(capturedChatOptions);
Assert.NotNull(capturedChatOptions.Reasoning);
Assert.Equal(requestReasoning.Effort, capturedChatOptions.Reasoning.Effort);
Assert.Equal(requestReasoning.Output, capturedChatOptions.Reasoning.Output);
}

/// <summary>
/// Verify that <see cref="ChatOptions.Reasoning"/> falls back to the agent's when the request has none.
/// </summary>
[Fact]
public async Task ChatOptionsMergingFallsBackToAgentReasoningWhenRequestHasNoneAsync()
{
// Arrange
var agentReasoning = new ReasoningOptions { Effort = ReasoningEffort.Low, Output = ReasoningOutput.Full };

Mock<IChatClient> mockService = new();
ChatOptions? capturedChatOptions = null;
mockService.Setup(
s => s.GetResponseAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<ChatOptions>(),
It.IsAny<CancellationToken>()))
.Callback<IEnumerable<ChatMessage>, ChatOptions, CancellationToken>((msgs, opts, ct) =>
capturedChatOptions = opts)
.ReturnsAsync(new ChatResponse([new(ChatRole.Assistant, "response")]));

ChatClientAgent agent = new(mockService.Object, options: new()
{
ChatOptions = new ChatOptions { Reasoning = agentReasoning }
});
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };

// Act
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(new ChatOptions()));

// Assert
Assert.NotNull(capturedChatOptions);
Assert.NotNull(capturedChatOptions.Reasoning);
Assert.Equal(agentReasoning.Effort, capturedChatOptions.Reasoning.Effort);
Assert.Equal(agentReasoning.Output, capturedChatOptions.Reasoning.Output);
}

/// <summary>
/// Verify that <see cref="ChatOptions.Reasoning"/> from the request is used when the agent has none.
/// </summary>
[Fact]
public async Task ChatOptionsMergingUsesRequestReasoningWhenAgentHasNoneAsync()
{
// Arrange
var requestReasoning = new ReasoningOptions { Effort = ReasoningEffort.High, Output = ReasoningOutput.Full };

Mock<IChatClient> mockService = new();
ChatOptions? capturedChatOptions = null;
mockService.Setup(
s => s.GetResponseAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<ChatOptions>(),
It.IsAny<CancellationToken>()))
.Callback<IEnumerable<ChatMessage>, ChatOptions, CancellationToken>((msgs, opts, ct) =>
capturedChatOptions = opts)
.ReturnsAsync(new ChatResponse([new(ChatRole.Assistant, "response")]));

ChatClientAgent agent = new(mockService.Object, options: new()
{
ChatOptions = new ChatOptions()
});
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };

// Act
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(new ChatOptions { Reasoning = requestReasoning }));

// Assert
Assert.NotNull(capturedChatOptions);
Assert.NotNull(capturedChatOptions.Reasoning);
Assert.Equal(requestReasoning.Effort, capturedChatOptions.Reasoning.Effort);
Assert.Equal(requestReasoning.Output, capturedChatOptions.Reasoning.Output);
}

/// <summary>
/// Verify that ChatOptions merging handles all scalar properties correctly.
/// </summary>
Expand Down
Loading