@@ -249,6 +249,32 @@ public static ReflectionAIFunctionDescriptor GetOrCreate(MethodInfo method, AIFu
249249
250250 private ReflectionAIFunctionDescriptor ( DescriptorKey key , JsonSerializerOptions serializerOptions )
251251 {
252+ AIJsonSchemaCreateOptions schemaOptions = new ( )
253+ {
254+ // This needs to be kept in sync with the shape of AIJsonSchemaCreateOptions.
255+ TransformSchemaNode = key . SchemaOptions . TransformSchemaNode ,
256+ IncludeParameter = parameterInfo =>
257+ {
258+ // Explicitly exclude from the schema CancellationToken parameters as well
259+ // as those annotated as [FromServices] or [FromKeyedServices]. These will be satisfied
260+ // from sources other than arguments to InvokeAsync.
261+ if ( parameterInfo . ParameterType == typeof ( CancellationToken ) ||
262+ parameterInfo . GetCustomAttribute < FromServicesAttribute > ( inherit : true ) is not null ||
263+ parameterInfo . GetCustomAttribute < FromKeyedServicesAttribute > ( inherit : true ) is not null )
264+ {
265+ return false ;
266+ }
267+
268+ // For all other parameters, delegate to whatever behavior is specified in the options.
269+ // If none is specified, include the parameter.
270+ return key . SchemaOptions . IncludeParameter ? . Invoke ( parameterInfo ) ?? true ;
271+ } ,
272+ IncludeTypeInEnumSchemas = key . SchemaOptions . IncludeTypeInEnumSchemas ,
273+ DisallowAdditionalProperties = key . SchemaOptions . DisallowAdditionalProperties ,
274+ IncludeSchemaKeyword = key . SchemaOptions . IncludeSchemaKeyword ,
275+ RequireAllProperties = key . SchemaOptions . RequireAllProperties ,
276+ } ;
277+
252278 // Get marshaling delegates for parameters.
253279 ParameterInfo [ ] parameters = key . Method . GetParameters ( ) ;
254280 ParameterMarshallers = new Func < IReadOnlyDictionary < string , object ? > , CancellationToken , object ? > [ parameters . Length ] ;
@@ -269,7 +295,7 @@ private ReflectionAIFunctionDescriptor(DescriptorKey key, JsonSerializerOptions
269295 Name ,
270296 Description ,
271297 serializerOptions ,
272- key . SchemaOptions ) ;
298+ schemaOptions ) ;
273299 }
274300
275301 public string Name { get ; }
@@ -343,33 +369,36 @@ static bool IsAsyncMethod(MethodInfo method)
343369 }
344370
345371 // For DI-based parameters, try to resolve from the service provider.
346- if ( parameter . GetCustomAttribute < FromServiceProviderAttribute > ( inherit : true ) is FromServiceProviderAttribute fspAttr )
372+ if ( parameter . GetCustomAttribute < FromServicesAttribute > ( inherit : true ) is { } fsAttr )
347373 {
348374 return ( arguments , _ ) =>
349375 {
350- if ( ( arguments as AIFunctionArguments ) ? . ServiceProvider is IServiceProvider services )
376+ if ( ( arguments as AIFunctionArguments ) ? . ServiceProvider is IServiceProvider services &&
377+ services . GetService ( parameterType ) is object service )
351378 {
352- if ( fspAttr . ServiceKey is object serviceKey )
353- {
354- if ( ( services as IKeyedServiceProvider ) ? . GetKeyedService ( parameterType , serviceKey ) is object keyedService )
355- {
356- return keyedService ;
357- }
358- }
359- else if ( services . GetService ( parameterType ) is object service )
360- {
361- return service ;
362- }
379+ return service ;
363380 }
364381
365- // No service could be resolved. Does it have a default value?
366- if ( parameter . HasDefaultValue )
382+ // No service could be resolved. Return a default value if it's optional, otherwise throw.
383+ return parameter . HasDefaultValue ?
384+ parameter . DefaultValue :
385+ throw new InvalidOperationException ( $ "Unable to resolve service of type '{ parameterType } ' for parameter '{ parameter . Name } '.") ;
386+ } ;
387+ }
388+ else if ( parameter . GetCustomAttribute < FromKeyedServicesAttribute > ( inherit : true ) is { } fksAttr )
389+ {
390+ return ( arguments , _ ) =>
391+ {
392+ if ( ( arguments as AIFunctionArguments ) ? . ServiceProvider is IKeyedServiceProvider services &&
393+ services . GetKeyedService ( parameterType , fksAttr . Key ) is object service )
367394 {
368- return parameter . DefaultValue ;
395+ return service ;
369396 }
370397
371- // It's a required argument, and we couldn't resolve a service. Throw.
372- throw new InvalidOperationException ( $ "Unable to resolve service of type '{ parameterType } ' for parameter '{ parameter . Name } '.") ;
398+ // No service could be resolved. Return a default value if it's optional, otherwise throw.
399+ return parameter . HasDefaultValue ?
400+ parameter . DefaultValue :
401+ throw new InvalidOperationException ( $ "Unable to resolve service of type '{ parameterType } ' with key '{ fksAttr . Key } ' for parameter '{ parameter . Name } '.") ;
373402 } ;
374403 }
375404
0 commit comments