Repository navigation
.NET: Terminating a Harness tool loop can omit completed function results from session history #9435
Description
Problem
With Microsoft.Agents.AI / Microsoft.Agents.AI.Harness 1.24.0, stopping a Harness tool loop through the documented FunctionInvocationContext.Terminate flag can leave the serialized session without the results of functions which have completed. A later run on the same session then lacks that evidence.
We discovered this while implementing incoming user corrections for an in-process channel Agent. We now use the existing native MessageInjectingChatClient.EnqueueMessagesAsync path for text steering instead of termination. This report concerns the termination/persistence contract, not a request to add a message injection API that already exists.
Application Reproduction and Evidence
- Create a HarnessAgent with an in-memory chat history provider and a real tool.
- The first model response requests one or two calls to that tool.
- Use function invocation middleware. Await
next(context, cancellationToken); only on the finalFunctionCallIndex == FunctionCount - 1, setcontext.Terminate = truewhen a new user correction is pending. - Await the agent run, serialize its session using the normal agent API, restore it, and start the next run with the user's new messages.
- Inspect the next model request.
Our application integration tests against a real HTTP protocol test provider observed both cases fail: the next request retained the original user input and the new messages, but contained zero tool-result messages instead of the expected one/two. The no-tool control passed. This is application-level evidence; we have not yet reduced it to a standalone upstream unit test.
The relevant source explains the apparent gap:
- Harness always composes function invocation, message injection and per-service-call history persistence: https://github.com/microsoft/agent-framework/blob/deecbcb062198f926516f89b65e5b1676e4514c2/dotnet/src/Microsoft.Agents.AI.Harness/HarnessAgent.cs
- The per-service-call decorator persists request messages plus the model response. Function results are produced after that service call: https://github.com/microsoft/agent-framework/blob/deecbcb062198f926516f89b65e5b1676e4514c2/dotnet/src/Microsoft.Agents.AI/ChatClient/PerServiceCallChatHistoryPersistingChatClient.cs
- ChatClientAgent skips end-of-run provider notification when per-service-call persistence owns history: https://github.com/microsoft/agent-framework/blob/deecbcb062198f926516f89b65e5b1676e4514c2/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs
The suspected result is that termination prevents the next service call that would otherwise persist the completed function-result input. Please confirm the intended contract.
Expected Behavior
After a successful run that ends through FunctionInvocationContext.Terminate, serializing/restoring its session preserves complete matching call/result pairs for every function that actually completed. Resuming must not lose those results or cause side-effecting tools to be repeated.
If termination deliberately cannot provide that guarantee with per-service-call persistence, please document that restriction on the public flag and describe a supported checkpoint/resume pattern. The native message injection queue is suitable for ordinary text steering, but does not define the full semantics of deliberate termination.
Alternatives Considered
- We use native message injection for incoming text corrections. This keeps the function loop and its normal history persistence intact.
- We did not disable Harness persistence, manually mutate its serialized JSON, recreate tool results, or run concurrent turns on one session.
- Cancelling tools cannot establish that external side effects stopped and is not a safe substitute for completed result persistence.
Scope
.NET Harness, function middleware, native session serialization and per-service-call persistence. One- and multiple-function batches, with regression coverage for session reuse after termination. No request to cancel already committed effects or to replace application-owned routing and durable admission.
Language
.NET
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
[-].NET: [Feature]: In-process active-run steering at safe tool-batch boundaries[/-][+].NET: Terminating a Harness tool loop can omit completed function results from session history[/+]