diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalResponseContent.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalResponseContent.cs
index ab073f36b2d..7a12aa1ca74 100644
--- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalResponseContent.cs
+++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalResponseContent.cs
@@ -42,5 +42,9 @@ public ToolApprovalResponseContent(string requestId, bool approved, ToolCallCont
///
/// Gets or sets the optional reason for the approval or rejection.
///
+ ///
+ /// When a function call is rejected by function invocation middleware, this reason is appended to the rejection message.
+ /// Callers can use the reason to indicate whether the rejection is final or a new call may be requested for approval.
+ ///
public string? Reason { get; set; }
}
diff --git a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs
index 0eb4bd29538..643c3e2178f 100644
--- a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs
+++ b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs
@@ -1552,7 +1552,7 @@ FunctionResultContent CreateFunctionResultContent(FunctionInvocationResult resul
{
LogFunctionRejected(m.ResponseFunctionCallContent.Name, m.Response.Reason);
- string result = "Tool call invocation was rejected by the approver and must not be retried.";
+ string result = "Tool call invocation rejected.";
if (!string.IsNullOrWhiteSpace(m.Response.Reason))
{
result = $"{result} {m.Response.Reason}";
diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs
index b6efd117377..535787748d8 100644
--- a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs
+++ b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs
@@ -435,8 +435,8 @@ public async Task RejectedApprovalResponsesAreFailedAsync()
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried."),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected."),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected.")
]),
];
@@ -450,8 +450,8 @@ public async Task RejectedApprovalResponsesAreFailedAsync()
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried."),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected."),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected.")
]),
new ChatMessage(ChatRole.Assistant, "world"),
];
@@ -492,7 +492,7 @@ public async Task MixedApprovedAndRejectedApprovalResponsesAreExecutedAndFailedA
[
new ChatMessage(ChatRole.User, "hello"),
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
- new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried.")]),
+ new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId1", result: "Tool call invocation rejected.")]),
new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId2", result: "Result 2: 42")]),
];
@@ -504,7 +504,7 @@ public async Task MixedApprovedAndRejectedApprovalResponsesAreExecutedAndFailedA
List nonStreamingOutput =
[
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
- new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried.")]),
+ new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId1", result: "Tool call invocation rejected.")]),
new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId2", result: "Result 2: 42")]),
new ChatMessage(ChatRole.Assistant, "world"),
];
@@ -514,7 +514,7 @@ public async Task MixedApprovedAndRejectedApprovalResponsesAreExecutedAndFailedA
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried."),
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected."),
new FunctionResultContent("callId2", result: "Result 2: 42")
]),
new ChatMessage(ChatRole.Assistant, "world"),
@@ -564,8 +564,8 @@ public async Task RejectedApprovalResponsesWithCustomReasonAsync()
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried. User denied permission for this operation"),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried. Function Func2 is not allowed at this time")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected. User denied permission for this operation"),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected. Function Func2 is not allowed at this time")
]),
];
@@ -579,8 +579,8 @@ public async Task RejectedApprovalResponsesWithCustomReasonAsync()
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried. User denied permission for this operation"),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried. Function Func2 is not allowed at this time")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected. User denied permission for this operation"),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected. Function Func2 is not allowed at this time")
]),
new ChatMessage(ChatRole.Assistant, "world"),
];
@@ -631,8 +631,8 @@ public async Task MixedApprovalResponsesWithCustomAndDefaultReasonsAsync()
]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried. Custom rejection for Func1"),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected. Custom rejection for Func1"),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected.")
]),
new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId3", result: "Result 3: test")]),
];
@@ -652,8 +652,8 @@ public async Task MixedApprovalResponsesWithCustomAndDefaultReasonsAsync()
]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried. Custom rejection for Func1"),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected. Custom rejection for Func1"),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected.")
]),
new ChatMessage(ChatRole.Tool, [new FunctionResultContent("callId3", result: "Result 3: test")]),
new ChatMessage(ChatRole.Assistant, "world"),
@@ -669,8 +669,8 @@ public async Task MixedApprovalResponsesWithCustomAndDefaultReasonsAsync()
]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried. Custom rejection for Func1"),
- new FunctionResultContent("callId2", result: "Tool call invocation was rejected by the approver and must not be retried."),
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected. Custom rejection for Func1"),
+ new FunctionResultContent("callId2", result: "Tool call invocation rejected."),
new FunctionResultContent("callId3", result: "Result 3: test")
]),
new ChatMessage(ChatRole.Assistant, "world"),
@@ -717,7 +717,7 @@ public async Task RejectedApprovalResponsesWithEmptyOrWhitespaceReasonUsesDefaul
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1")]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected.")
]),
];
@@ -731,7 +731,7 @@ public async Task RejectedApprovalResponsesWithEmptyOrWhitespaceReasonUsesDefaul
new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1")]),
new ChatMessage(ChatRole.Tool,
[
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected.")
]),
new ChatMessage(ChatRole.Assistant, "world"),
];
@@ -1944,7 +1944,7 @@ public async Task RejectedApprovalResponses_MixedWithMcpApprovalAsync(bool useAd
[
approveFuncCall ?
new FunctionResultContent("callId1", result: "Result 1") :
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected.")
]),
new ChatMessage(ChatRole.User,
[
@@ -1971,7 +1971,7 @@ [new McpServerToolResultContent("callId2") { Outputs = [new TextContent("Result
[
approveFuncCall ?
new FunctionResultContent("callId1", result: "Result 1") :
- new FunctionResultContent("callId1", result: "Tool call invocation was rejected by the approver and must not be retried.")
+ new FunctionResultContent("callId1", result: "Tool call invocation rejected.")
]),
new ChatMessage(ChatRole.Assistant, [
new TextContent("world"),