-
Notifications
You must be signed in to change notification settings - Fork 851
Add IterationCompleted delegate to FunctionInvokingChatClient to facilitate agentic patterns #7251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
PederHP
wants to merge
2
commits into
dotnet:main
Choose a base branch
from
PederHP:meai_function_invocation_hook
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
70 changes: 70 additions & 0 deletions
70
src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvocationIterationContext.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using Microsoft.Shared.DiagnosticIds; | ||
| using Microsoft.Shared.Diagnostics; | ||
|
|
||
| namespace Microsoft.Extensions.AI; | ||
|
|
||
| /// <summary>Provides context for an iteration within the function invocation loop.</summary> | ||
| /// <remarks> | ||
| /// This context is provided to the <see cref="FunctionInvokingChatClient.IterationCompleted"/> | ||
| /// callback after each iteration of the function invocation loop completes. | ||
| /// </remarks> | ||
| [Experimental(DiagnosticIds.Experiments.AIIterationCompleted, UrlFormat = DiagnosticIds.UrlFormat)] | ||
| public class FunctionInvocationIterationContext | ||
| { | ||
| /// <summary>Gets or sets the current iteration number (0-based).</summary> | ||
| /// <remarks> | ||
| /// The initial request to the client that passes along the chat contents provided to the | ||
| /// <see cref="FunctionInvokingChatClient"/> is iteration 0. If the client responds with | ||
| /// a function call request that is processed, the next iteration is 1, and so on. | ||
| /// </remarks> | ||
| public int Iteration { get; set; } | ||
|
|
||
| /// <summary>Gets or sets the aggregated usage details across all iterations so far.</summary> | ||
| /// <remarks> | ||
| /// This includes usage from all inner client calls and is updated after each iteration. | ||
| /// May be <see langword="null"/> if the inner client doesn't provide usage information. | ||
| /// </remarks> | ||
| public UsageDetails? TotalUsage { get; set; } | ||
|
|
||
| /// <summary>Gets or sets the messages accumulated during the function-calling loop.</summary> | ||
| /// <remarks> | ||
| /// This includes all messages from all iterations, including function call and result contents. | ||
| /// </remarks> | ||
| public IReadOnlyList<ChatMessage> Messages | ||
| { | ||
| get; | ||
| set => field = Throw.IfNull(value); | ||
| } = []; | ||
|
|
||
| /// <summary>Gets or sets the response from the most recent inner client call.</summary> | ||
| /// <remarks> | ||
| /// This is the response that triggered the current iteration's function invocations. | ||
| /// </remarks> | ||
| public ChatResponse Response | ||
| { | ||
| get; | ||
| set => field = Throw.IfNull(value); | ||
| } = new([]); | ||
|
|
||
| /// <summary>Gets or sets a value indicating whether to terminate the loop after this iteration.</summary> | ||
| /// <remarks> | ||
| /// <para> | ||
| /// Setting this to <see langword="true"/> will cause the function invocation loop to exit | ||
| /// after the current iteration completes. The function calls for this iteration will have | ||
| /// already been processed before this callback is invoked. | ||
| /// </para> | ||
| /// <para> | ||
| /// This is similar to setting <see cref="FunctionInvocationContext.Terminate"/> from within | ||
| /// a function, but can be triggered based on external criteria like usage thresholds. | ||
| /// </para> | ||
| /// </remarks> | ||
| public bool Terminate { get; set; } | ||
|
|
||
| /// <summary>Gets or sets a value indicating whether the iteration is part of a streaming operation.</summary> | ||
| public bool IsStreaming { get; set; } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Immutable? You mentioned wanting to use this for context compaction... how are you doing that?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outside of the loop. This is purely for inspection, to be able to break out of the agentic loop without being forced to do so during a function invocation. If some condition happens during the tool call - I trigger the exit - and I then compact the context (usually not compacting the tool call but doing so further down the message stack), and then re-invoke the IChatClient.
So what I'm looking for is not to be able to mutate the context inside the loop (although to be honest that would be great, but I seem to recall it would require bigger changes, and I found a workaround for having mutable system context during the loop so that's good enough for me).
The current FunctionInvoker allows for aborting a call in a somewhat destructive, messy manner - I want to signal a loop exit in a cleaner way. Finish the current tool (or tools if parallel) and then return - then I can decide what to do and reinvoke the client. Currently the FICC is very closed, and this was the least invasive way I could find to break the loop.
If you think there are better ways, I am happy to try and rework this. But I think FunctionInvoker and Terminate is too limited for modern long-lived agentic flows.