Skip to content

Commit f8d25f4

Browse files
authored
Enhance Function Invocation Extensibility for Microsoft.Extensions.AI (#6325)
1 parent a7f06f2 commit f8d25f4

File tree

5 files changed

+287
-71
lines changed

5 files changed

+287
-71
lines changed

src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionArguments.cs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#pragma warning disable SA1111 // Closing parenthesis should be on line of last parameter
99
#pragma warning disable SA1112 // Closing parenthesis should be on line of opening parenthesis
1010
#pragma warning disable SA1114 // Parameter list should follow declaration
11+
#pragma warning disable S3358 // Extract this nested ternary operation into an independent statement.
12+
#pragma warning disable S1067 // Expressions should not be too complex
13+
#pragma warning disable S4039 // Make 'AIFunctionArguments' sealed
14+
#pragma warning disable CA1033 // Make 'AIFunctionArguments' sealed
1115
#pragma warning disable CA1710 // Identifiers should have correct suffix
1216

1317
namespace Microsoft.Extensions.AI;
@@ -20,15 +24,16 @@ namespace Microsoft.Extensions.AI;
2024
/// an <see cref="AIFunction"/> if it needs to resolve any services from a dependency injection
2125
/// container.
2226
/// </remarks>
23-
public sealed class AIFunctionArguments : IDictionary<string, object?>, IReadOnlyDictionary<string, object?>
27+
public class AIFunctionArguments : IDictionary<string, object?>, IReadOnlyDictionary<string, object?>
2428
{
2529
/// <summary>The nominal arguments.</summary>
2630
private readonly Dictionary<string, object?> _arguments;
2731

28-
/// <summary>Initializes a new instance of the <see cref="AIFunctionArguments"/> class.</summary>
32+
/// <summary>Initializes a new instance of the <see cref="AIFunctionArguments"/> class, and uses the default comparer for key comparisons.</summary>
33+
/// <remarks>The <see cref="IEqualityComparer{T}"/> is ordinal by default.</remarks>
2934
public AIFunctionArguments()
35+
: this(null, null)
3036
{
31-
_arguments = [];
3237
}
3338

3439
/// <summary>
@@ -42,14 +47,44 @@ public AIFunctionArguments()
4247
/// operations on this instance will be routed directly to that instance. If <paramref name="arguments"/>
4348
/// is not a dictionary, a shallow clone of its data will be used to populate this
4449
/// instance. A <see langword="null"/> <paramref name="arguments"/> is treated as an
45-
/// empty dictionary.
50+
/// empty parameters dictionary.
51+
/// The <see cref="IEqualityComparer{T}"/> is ordinal by default.
4652
/// </remarks>
4753
public AIFunctionArguments(IDictionary<string, object?>? arguments)
54+
: this(arguments, null)
55+
{
56+
}
57+
58+
/// <summary>Initializes a new instance of the <see cref="AIFunctionArguments"/> class.</summary>
59+
/// <param name="comparer">The <see cref="IEqualityComparer{T}"/> to use for key comparisons.</param>
60+
public AIFunctionArguments(IEqualityComparer<string>? comparer)
61+
: this(null, comparer)
62+
{
63+
}
64+
65+
/// <summary>
66+
/// Initializes a new instance of the <see cref="AIFunctionArguments"/> class containing
67+
/// the specified <paramref name="arguments"/>.
68+
/// </summary>
69+
/// <param name="arguments">The arguments represented by this instance.</param>
70+
/// <param name="comparer">The <see cref="IEqualityComparer{T}"/> to be used.</param>
71+
/// <remarks>
72+
/// The <paramref name="arguments"/> reference will be stored if the instance is already a
73+
/// <see cref="Dictionary{TKey, TValue}"/> with the same <see cref="IEqualityComparer{T}"/> or if
74+
/// <paramref name="arguments"/> is <see langword="null" /> in which case all dictionary operations
75+
/// on this instance will be routed directly to that instance otherwise a shallow clone of the provided <paramref name="arguments"/>.
76+
/// A <see langword="null"/> <paramref name="arguments"/> is will be treated as an empty parameters dictionary.
77+
/// </remarks>
78+
public AIFunctionArguments(IDictionary<string, object?>? arguments, IEqualityComparer<string>? comparer)
4879
{
80+
#pragma warning disable S1698 // Consider using 'Equals' if value comparison is intended.
4981
_arguments =
50-
arguments is null ? [] :
51-
arguments as Dictionary<string, object?> ??
52-
new Dictionary<string, object?>(arguments);
82+
arguments is null
83+
? new Dictionary<string, object?>(comparer)
84+
: (arguments is Dictionary<string, object?> dc) && (comparer is null || dc.Comparer == comparer)
85+
? dc
86+
: new Dictionary<string, object?>(arguments, comparer);
87+
#pragma warning restore S1698 // Consider using 'Equals' if value comparison is intended.
5388
}
5489

5590
/// <summary>Gets or sets services optionally associated with these arguments.</summary>

src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvocationContext.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace Microsoft.Extensions.AI;
1010

1111
/// <summary>Provides context for an in-flight function invocation.</summary>
12-
public sealed class FunctionInvocationContext
12+
public class FunctionInvocationContext
1313
{
1414
/// <summary>
1515
/// A nop function used to allow <see cref="Function"/> to be non-nullable. Default instances of
@@ -92,6 +92,16 @@ public IList<ChatMessage> Messages
9292
/// and a new request issued to the wrapped client. If this property is set to <see langword="true"/>, that subsequent request
9393
/// will not be issued and instead the loop immediately terminated rather than continuing until there are no
9494
/// more function call requests in responses.
95+
/// <para>
96+
/// If multiple function call requests are issued as part of a single iteration (a single response from the inner <see cref="IChatClient"/>),
97+
/// setting <see cref="Terminate" /> to <see langword="true" /> may also prevent subsequent requests within that same iteration from being processed.
98+
/// </para>
9599
/// </remarks>
96100
public bool Terminate { get; set; }
101+
102+
/// <summary>
103+
/// Gets or sets a value indicating whether the function invocation is occurring as part of a
104+
/// <see cref="IChatClient.GetStreamingResponseAsync"/> call as opposed to a <see cref="IChatClient.GetResponseAsync"/> call.
105+
/// </summary>
106+
public bool IsStreaming { get; set; }
97107
}

0 commit comments

Comments
 (0)