Skip to content

Commit da8a275

Browse files
Copilotstephentoub
andcommitted
Fix CI failures by resetting InvocationRequired in test helper methods
The tests reuse FunctionCallContent objects across multiple test iterations. When we set InvocationRequired=false during processing, subsequent test iterations see them as already processed. Fixed by resetting InvocationRequired=true at the beginning of InvokeAndAssertAsync and InvokeAndAssertStreamingAsync helper methods. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
1 parent c4f504a commit da8a275

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ public async Task SupportsToolsProvidedByAdditionalTools(bool provideOptions)
136136

137137
await InvokeAndAssertAsync(options, plan, configurePipeline: configure);
138138

139+
ResetPlanFunctionCallStates(plan);
139140
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configure);
140141
}
141142

@@ -169,6 +170,7 @@ public async Task PrefersToolsProvidedByChatOptions()
169170

170171
await InvokeAndAssertAsync(options, plan, configurePipeline: configure);
171172

173+
ResetPlanFunctionCallStates(plan);
172174
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configure);
173175
}
174176

@@ -219,6 +221,7 @@ public async Task SupportsMultipleFunctionCallsPerRequestAsync(bool concurrentIn
219221

220222
await InvokeAndAssertAsync(options, plan, configurePipeline: configure);
221223

224+
ResetPlanFunctionCallStates(plan);
222225
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configure);
223226
}
224227

@@ -267,6 +270,7 @@ public async Task ParallelFunctionCallsMayBeInvokedConcurrentlyAsync()
267270

268271
await InvokeAndAssertAsync(options, plan, configurePipeline: configure);
269272

273+
ResetPlanFunctionCallStates(plan);
270274
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configure);
271275
}
272276

@@ -308,6 +312,7 @@ public async Task ConcurrentInvocationOfParallelCallsDisabledByDefaultAsync()
308312

309313
await InvokeAndAssertAsync(options, plan);
310314

315+
ResetPlanFunctionCallStates(plan);
311316
await InvokeAndAssertStreamingAsync(options, plan);
312317
}
313318

@@ -351,6 +356,7 @@ public async Task FunctionInvokerDelegateOverridesHandlingAsync()
351356

352357
await InvokeAndAssertAsync(options, plan, configurePipeline: configure);
353358

359+
ResetPlanFunctionCallStates(plan);
354360
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configure);
355361
}
356362

@@ -562,6 +568,7 @@ public async Task KeepsFunctionCallingContent()
562568
#pragma warning disable SA1005, S125
563569
Validate(await InvokeAndAssertAsync(options, plan));
564570

571+
ResetPlanFunctionCallStates(plan);
565572
Validate(await InvokeAndAssertStreamingAsync(options, plan));
566573

567574
static void Validate(List<ChatMessage> finalChat)
@@ -597,6 +604,7 @@ public async Task ExceptionDetailsOnlyReportedWhenRequestedAsync(bool detailedEr
597604

598605
await InvokeAndAssertAsync(options, plan, configurePipeline: configure);
599606

607+
ResetPlanFunctionCallStates(plan);
600608
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configure);
601609
}
602610

@@ -1077,6 +1085,7 @@ public async Task FunctionInvocations_InvokedOnOriginalSynchronizationContext()
10771085
.UseFunctionInvocation(configure: c => { c.AllowConcurrentInvocation = true; c.IncludeDetailedErrors = true; });
10781086

10791087
await InvokeAndAssertAsync(options, plan, configurePipeline: configurePipeline);
1088+
ResetPlanFunctionCallStates(plan);
10801089
await InvokeAndAssertStreamingAsync(options, plan, configurePipeline: configurePipeline);
10811090
}
10821091

@@ -1110,6 +1119,7 @@ public async Task TerminateOnUnknownCalls_ControlsBehaviorForUnknownFunctions(bo
11101119
];
11111120

11121121
await InvokeAndAssertAsync(options, planForContinue, configurePipeline: configure);
1122+
ResetPlanFunctionCallStates(planForContinue);
11131123
await InvokeAndAssertStreamingAsync(options, planForContinue, configurePipeline: configure);
11141124
}
11151125
else
@@ -1621,6 +1631,9 @@ private static async Task<List<ChatMessage>> InvokeAndAssertAsync(
16211631
{
16221632
Assert.NotEmpty(plan);
16231633

1634+
// Reset InvocationRequired for all FunctionCallContent in the plan to allow reuse
1635+
ResetPlanFunctionCallStates(plan);
1636+
16241637
configurePipeline ??= static b => b.UseFunctionInvocation();
16251638

16261639
using CancellationTokenSource cts = new();
@@ -1691,6 +1704,9 @@ private static async Task<List<ChatMessage>> InvokeAndAssertStreamingAsync(
16911704
{
16921705
Assert.NotEmpty(plan);
16931706

1707+
// Reset InvocationRequired for all FunctionCallContent in the plan to allow reuse
1708+
ResetPlanFunctionCallStates(plan);
1709+
16941710
configurePipeline ??= static b => b.UseFunctionInvocation();
16951711

16961712
using CancellationTokenSource cts = new();
@@ -1731,4 +1747,22 @@ private static async IAsyncEnumerable<T> YieldAsync<T>(params IEnumerable<T> ite
17311747
yield return item;
17321748
}
17331749
}
1750+
1751+
/// <summary>
1752+
/// Resets InvocationRequired to true for all FunctionCallContent in the plan.
1753+
/// This is needed when reusing a plan across multiple test invocations.
1754+
/// </summary>
1755+
private static void ResetPlanFunctionCallStates(List<ChatMessage> plan)
1756+
{
1757+
foreach (var message in plan)
1758+
{
1759+
foreach (var content in message.Contents)
1760+
{
1761+
if (content is FunctionCallContent fcc)
1762+
{
1763+
fcc.InvocationRequired = true;
1764+
}
1765+
}
1766+
}
1767+
}
17341768
}

0 commit comments

Comments
 (0)