From f51a7f6be3bc2afa7fa99f409b463bfd9e7017e5 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 7 Apr 2025 10:05:06 -0400 Subject: [PATCH] Augment AIFunctionFactory.Create XML docs --- .../Functions/AIFunctionFactory.cs | 397 +++++++++++++++--- 1 file changed, 338 insertions(+), 59 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactory.cs b/src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactory.cs index 41550ba0451..5116238763f 100644 --- a/src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactory.cs +++ b/src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactory.cs @@ -41,15 +41,67 @@ public static partial class AIFunctionFactory /// The created for invoking . /// /// - /// Return values are serialized to using 's - /// . Arguments that are not already of the expected type are - /// marshaled to the expected type via JSON and using 's - /// . If the argument is a , - /// , or , it is deserialized directly. If the argument is anything else unknown, - /// it is round-tripped through JSON, serializing the object as JSON and then deserializing it to the expected type. + /// By default, any parameters to are sourced from the 's dictionary + /// of key/value pairs and are represented in the JSON schema for the function, as exposed in the returned 's + /// . There are a few exceptions to this: + /// + /// + /// + /// parameters are automatically bound to the passed into + /// the invocation via 's parameter. The parameter is + /// not included in the generated JSON schema. The behavior of parameters may not be overridden. + /// + /// + /// + /// + /// By default, parameters are bound from the property + /// and are not included in the JSON schema. If the parameter is optional, such that a default value is provided, + /// is allowed to be ; otherwise, + /// must be non-, or else the invocation will fail with an exception due to the required nature of the parameter. + /// The handling of parameters may be overridden via . + /// + /// + /// + /// + /// By default, parameters are bound directly to instance + /// passed into and are not included in the JSON schema. If the + /// instance passed to is , the implementation + /// manufactures an empty instance, such that parameters of type may always be satisfied, whether + /// optional or not. The handling of parameters may be overridden via + /// . + /// + /// + /// + /// All other parameter types are, by default, bound from the dictionary passed into + /// and are included in the generated JSON schema. This may be overridden by the provided + /// via the parameter; for every parameter, the delegate is enabled to choose if the parameter should be included in the + /// generated schema and how its value should be bound, including handling of optionality (by default, required parameters that are not included in the + /// dictionary will result in an exception being thrown). Loosely-typed additional context information may be passed + /// into via the 's dictionary; the default + /// binding ignores this collection, but a custom binding supplied via may choose to + /// source arguments from this data. + /// + /// + /// The default marshaling of parameters from the dictionary permits values to be passed into the 's + /// invocation directly if the object is already of a compatible type. Otherwise, if the argument is a , , + /// or , it is deserialized into the parameter type, utilizing if provided, + /// or else using . If the argument is anything else, it is round-tripped through JSON, serializing the object as JSON + /// and then deserializing it to the expected type. + /// + /// + /// In general, the data supplied via an 's dictionary is supplied from an AI service and should be considered + /// unvalidated and untrusted. To provide validated and trusted data to the invocation of , consider having + /// point to an instance method on an instance configured to hold the appropriate state. An parameter may also be + /// used to resolve services from a dependency injection container. + /// + /// + /// By default, return values are serialized to using 's + /// if provided, or else using . + /// Handling of return values may be overridden via . /// /// /// is . + /// A parameter to is not serializable. public static AIFunction Create(Delegate method, AIFunctionFactoryOptions? options) { _ = Throw.IfNull(method); @@ -59,20 +111,72 @@ public static AIFunction Create(Delegate method, AIFunctionFactoryOptions? optio /// Creates an instance for a method, specified via a delegate. /// The method to be represented via the created . - /// The name to use for the . - /// The description to use for the . + /// + /// The name to use for the . If , the name will be derived from + /// the name of . + /// + /// + /// The description to use for the . If , a description will be derived from + /// any on , if available. + /// /// The used to marshal function parameters and any return value. /// The created for invoking . /// /// - /// Return values are serialized to using . - /// Arguments that are not already of the expected type are marshaled to the expected type via JSON and using - /// . If the argument is a , , - /// or , it is deserialized directly. If the argument is anything else unknown, it is - /// round-tripped through JSON, serializing the object as JSON and then deserializing it to the expected type. + /// Any parameters to are sourced from the 's dictionary + /// of key/value pairs and are represented in the JSON schema for the function, as exposed in the returned 's + /// . There are a few exceptions to this: + /// + /// + /// + /// parameters are automatically bound to the passed into + /// the invocation via 's parameter. The parameter is + /// not included in the generated JSON schema. The behavior of parameters may not be overridden. + /// + /// + /// + /// + /// By default, parameters are bound from the property + /// and are not included in the JSON schema. If the parameter is optional, such that a default value is provided, + /// is allowed to be ; otherwise, + /// must be non-, or else the invocation will fail with an exception due to the required nature of the parameter. + /// The handling of parameters may be overridden via . + /// + /// + /// + /// + /// By default, parameters are bound directly to instance + /// passed into and are not included in the JSON schema. If the + /// instance passed to is , the implementation + /// manufactures an empty instance, such that parameters of type may always be satisfied, whether + /// optional or not. The handling of parameters may be overridden via + /// . + /// + /// + /// + /// All other parameter types are bound from the dictionary passed into + /// and are included in the generated JSON schema. + /// + /// + /// The marshaling of parameters from the dictionary permits values to be passed into the 's + /// invocation directly if the object is already of a compatible type. Otherwise, if the argument is a , , + /// or , it is deserialized into the parameter type, utilizing if provided, or else + /// . If the argument is anything else, it is round-tripped through JSON, serializing the object as JSON + /// and then deserializing it to the expected type. + /// + /// + /// In general, the data supplied via an 's dictionary is supplied from an AI service and should be considered + /// unvalidated and untrusted. To provide validated and trusted data to the invocation of , consider having + /// point to an instance method on an instance configured to hold the appropriate state. An parameter may also be + /// used to resolve services from a dependency injection container. + /// + /// + /// Return values are serialized to using if provided, + /// or else using . /// /// /// is . + /// A parameter to is not serializable. public static AIFunction Create(Delegate method, string? name = null, string? description = null, JsonSerializerOptions? serializerOptions = null) { _ = Throw.IfNull(method); @@ -102,15 +206,70 @@ public static AIFunction Create(Delegate method, string? name = null, string? de /// The created for invoking . /// /// - /// Return values are serialized to using 's - /// . Arguments that are not already of the expected type are - /// marshaled to the expected type via JSON and using 's - /// . If the argument is a , - /// , or , it is deserialized directly. If the argument is anything else unknown, - /// it is round-tripped through JSON, serializing the object as JSON and then deserializing it to the expected type. + /// By default, any parameters to are sourced from the 's dictionary + /// of key/value pairs and are represented in the JSON schema for the function, as exposed in the returned 's + /// . There are a few exceptions to this: + /// + /// + /// + /// parameters are automatically bound to the passed into + /// the invocation via 's parameter. The parameter is + /// not included in the generated JSON schema. The behavior of parameters may not be overridden. + /// + /// + /// + /// + /// By default, parameters are bound from the property + /// and are not included in the JSON schema. If the parameter is optional, such that a default value is provided, + /// is allowed to be ; otherwise, + /// must be non-, or else the invocation will fail with an exception due to the required nature of the parameter. + /// The handling of parameters may be overridden via . + /// + /// + /// + /// + /// By default, parameters are bound directly to instance + /// passed into and are not included in the JSON schema. If the + /// instance passed to is , the implementation + /// manufactures an empty instance, such that parameters of type may always be satisfied, whether + /// optional or not. The handling of parameters may be overridden via + /// . + /// + /// + /// + /// All other parameter types are, by default, bound from the dictionary passed into + /// and are included in the generated JSON schema. This may be overridden by the provided + /// via the parameter; for every parameter, the delegate is enabled to choose if the parameter should be included in the + /// generated schema and how its value should be bound, including handling of optionality (by default, required parameters that are not included in the + /// dictionary will result in an exception being thrown). Loosely-typed additional context information may be passed + /// into via the 's dictionary; the default + /// binding ignores this collection, but a custom binding supplied via may choose to + /// source arguments from this data. + /// + /// + /// The default marshaling of parameters from the dictionary permits values to be passed into the 's + /// invocation directly if the object is already of a compatible type. Otherwise, if the argument is a , , + /// or , it is deserialized into the parameter type, utilizing if provided, + /// or else using . If the argument is anything else, it is round-tripped through JSON, serializing the object as JSON + /// and then deserializing it to the expected type. + /// + /// + /// In general, the data supplied via an 's dictionary is supplied from an AI service and should be considered + /// unvalidated and untrusted. To provide validated and trusted data to the invocation of , consider having + /// point to an instance method on an instance configured to hold the appropriate state. An parameter may also be + /// used to resolve services from a dependency injection container. + /// + /// + /// By default, return values are serialized to using 's + /// if provided, or else using . + /// Handling of return values may be overridden via . /// /// /// is . + /// represents an instance method but is null. + /// represents an open generic method. + /// contains a parameter without a parameter name. + /// A parameter to or its return type is not serializable. public static AIFunction Create(MethodInfo method, object? target, AIFunctionFactoryOptions? options) { _ = Throw.IfNull(method); @@ -118,6 +277,100 @@ public static AIFunction Create(MethodInfo method, object? target, AIFunctionFac return ReflectionAIFunction.Build(method, target, options ?? _defaultOptions); } + /// + /// Creates an instance for a method, specified via an instance + /// and an optional target object if the method is an instance method. + /// + /// The method to be represented via the created . + /// + /// The target object for the if it represents an instance method. + /// This should be if and only if is a static method. + /// + /// + /// The name to use for the . If , the name will be derived from + /// the name of . + /// + /// + /// The description to use for the . If , a description will be derived from + /// any on , if available. + /// + /// The used to marshal function parameters and return value. + /// The created for invoking . + /// + /// + /// Any parameters to are sourced from the 's dictionary + /// of key/value pairs and are represented in the JSON schema for the function, as exposed in the returned 's + /// . There are a few exceptions to this: + /// + /// + /// + /// parameters are automatically bound to the passed into + /// the invocation via 's parameter. The parameter is + /// not included in the generated JSON schema. The behavior of parameters may not be overridden. + /// + /// + /// + /// + /// By default, parameters are bound from the property + /// and are not included in the JSON schema. If the parameter is optional, such that a default value is provided, + /// is allowed to be ; otherwise, + /// must be non-, or else the invocation will fail with an exception due to the required nature of the parameter. + /// The handling of parameters may be overridden via . + /// + /// + /// + /// + /// By default, parameters are bound directly to instance + /// passed into and are not included in the JSON schema. If the + /// instance passed to is , the implementation + /// manufactures an empty instance, such that parameters of type may always be satisfied, whether + /// optional or not. The handling of parameters may be overridden via + /// . + /// + /// + /// + /// All other parameter types are bound from the dictionary passed into + /// and are included in the generated JSON schema. + /// + /// + /// The marshaling of parameters from the dictionary permits values to be passed into the 's + /// invocation directly if the object is already of a compatible type. Otherwise, if the argument is a , , + /// or , it is deserialized into the parameter type, utilizing if provided, or else + /// . If the argument is anything else, it is round-tripped through JSON, serializing the object as JSON + /// and then deserializing it to the expected type. + /// + /// + /// In general, the data supplied via an 's dictionary is supplied from an AI service and should be considered + /// unvalidated and untrusted. To provide validated and trusted data to the invocation of , consider having + /// point to an instance method on an instance configured to hold the appropriate state. An parameter may also be + /// used to resolve services from a dependency injection container. + /// + /// + /// Return values are serialized to using if provided, + /// or else using . + /// + /// + /// is . + /// represents an instance method but is null. + /// represents an open generic method. + /// contains a parameter without a parameter name. + /// A parameter to or its return type is not serializable. + public static AIFunction Create(MethodInfo method, object? target, string? name = null, string? description = null, JsonSerializerOptions? serializerOptions = null) + { + _ = Throw.IfNull(method); + + AIFunctionFactoryOptions createOptions = serializerOptions is null && name is null && description is null + ? _defaultOptions + : new() + { + Name = name, + Description = description, + SerializerOptions = serializerOptions, + }; + + return ReflectionAIFunction.Build(method, target, createOptions); + } + /// /// Creates an instance for a method, specified via an for /// and instance method, along with a representing the type of the target object to @@ -127,7 +380,7 @@ public static AIFunction Create(MethodInfo method, object? target, AIFunctionFac /// /// The to construct an instance of on which to invoke when /// the resulting is invoked. If is provided, - /// ActivatorUtilities.CreateInstance will be used to construct the instance using those services; otherwise, + /// will be used to construct the instance using those services; otherwise, /// is used, utilizing the type's public parameterless constructor. /// If an instance can't be constructed, an exception is thrown during the function's invocation. /// @@ -142,8 +395,73 @@ public static AIFunction Create(MethodInfo method, object? target, AIFunctionFac /// , or , it is deserialized directly. If the argument is anything else unknown, /// it is round-tripped through JSON, serializing the object as JSON and then deserializing it to the expected type. /// + /// + /// By default, any parameters to are sourced from the 's dictionary + /// of key/value pairs and are represented in the JSON schema for the function, as exposed in the returned 's + /// . There are a few exceptions to this: + /// + /// + /// + /// parameters are automatically bound to the passed into + /// the invocation via 's parameter. The parameter is + /// not included in the generated JSON schema. The behavior of parameters may not be overridden. + /// + /// + /// + /// + /// By default, parameters are bound from the property + /// and are not included in the JSON schema. If the parameter is optional, such that a default value is provided, + /// is allowed to be ; otherwise, + /// must be non-, or else the invocation will fail with an exception due to the required nature of the parameter. + /// The handling of parameters may be overridden via . + /// + /// + /// + /// + /// By default, parameters are bound directly to instance + /// passed into and are not included in the JSON schema. If the + /// instance passed to is , the implementation + /// manufactures an empty instance, such that parameters of type may always be satisfied, whether + /// optional or not. The handling of parameters may be overridden via + /// . + /// + /// + /// + /// All other parameter types are, by default, bound from the dictionary passed into + /// and are included in the generated JSON schema. This may be overridden by the provided + /// via the parameter; for every parameter, the delegate is enabled to choose if the parameter should be included in the + /// generated schema and how its value should be bound, including handling of optionality (by default, required parameters that are not included in the + /// dictionary will result in an exception being thrown). Loosely-typed additional context information may be passed + /// into via the 's dictionary; the default + /// binding ignores this collection, but a custom binding supplied via may choose to + /// source arguments from this data. + /// + /// + /// The default marshaling of parameters from the dictionary permits values to be passed into the 's + /// invocation directly if the object is already of a compatible type. Otherwise, if the argument is a , , + /// or , it is deserialized into the parameter type, utilizing if provided, + /// or else using . If the argument is anything else, it is round-tripped through JSON, serializing the object as JSON + /// and then deserializing it to the expected type. + /// + /// + /// In general, the data supplied via an 's dictionary is supplied from an AI service and should be considered + /// unvalidated and untrusted. To provide validated and trusted data to the invocation of , the instance constructed + /// for each invocation may contain that data in it, such that it's then available to as instance data. + /// An parameter may also be used to resolve services from a dependency injection container. + /// + /// + /// By default, return values are serialized to using 's + /// if provided, or else using . + /// Handling of return values may be overridden via . + /// /// /// is . + /// is . + /// represents a static method. + /// represents an open generic method. + /// contains a parameter without a parameter name. + /// is not assignable to 's declaring type. + /// A parameter to or its return type is not serializable. public static AIFunction Create( MethodInfo method, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type targetType, @@ -155,45 +473,6 @@ public static AIFunction Create( return ReflectionAIFunction.Build(method, targetType, options ?? _defaultOptions); } - /// - /// Creates an instance for a method, specified via an instance - /// and an optional target object if the method is an instance method. - /// - /// The method to be represented via the created . - /// - /// The target object for the if it represents an instance method. - /// This should be if and only if is a static method. - /// - /// The name to use for the . - /// The description to use for the . - /// The used to marshal function parameters and return value. - /// The created for invoking . - /// - /// - /// Return values are serialized to using . - /// Arguments that are not already of the expected type are marshaled to the expected type via JSON and using - /// . If the argument is a , , - /// or , it is deserialized directly. If the argument is anything else unknown, it is - /// round-tripped through JSON, serializing the object as JSON and then deserializing it to the expected type. - /// - /// - /// is . - public static AIFunction Create(MethodInfo method, object? target, string? name = null, string? description = null, JsonSerializerOptions? serializerOptions = null) - { - _ = Throw.IfNull(method); - - AIFunctionFactoryOptions createOptions = serializerOptions is null && name is null && description is null - ? _defaultOptions - : new() - { - Name = name, - Description = description, - SerializerOptions = serializerOptions, - }; - - return ReflectionAIFunction.Build(method, target, createOptions); - } - private sealed class ReflectionAIFunction : AIFunction { public static ReflectionAIFunction Build(MethodInfo method, object? target, AIFunctionFactoryOptions options)