Files
agent-framework/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentSkillScriptAttribute.cs
T
e5f7b9c260 .NET: Support reflection for discovery of resources and scripts in class-based skills (#5183)
* support reflection for discovery of resources and scripts in class-based skills

* fix format issues

* refactor samples to use reflection

* Validate resource member signatures during discovery

Add discovery-time validation in AgentClassSkill.DiscoverResources() to
fail fast when [AgentSkillResource] is applied to members with incompatible
signatures:

- Reject indexer properties (getter has parameters)
- Reject methods with parameters other than IServiceProvider or
  CancellationToken

Throws InvalidOperationException with actionable error messages instead of
allowing silent runtime failures when ReadAsync invokes the AIFunction with
no named arguments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* prevent duplicates

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 11:56:28 +01:00

73 lines
2.6 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Shared.DiagnosticIds;
namespace Microsoft.Agents.AI;
/// <summary>
/// Marks a method as a skill script that is automatically discovered by <see cref="AgentClassSkill{TSelf}"/>.
/// </summary>
/// <remarks>
/// <para>
/// Apply this attribute to methods in an <see cref="AgentClassSkill{TSelf}"/> subclass to register them as
/// skill scripts. The method's parameters and return type are automatically marshaled via
/// <c>AIFunctionFactory</c>.
/// </para>
/// <para>
/// To provide a description for the script, apply <see cref="DescriptionAttribute"/>
/// to the same method.
/// </para>
/// <para>
/// Methods can be instance or static, and may have any visibility (public, private, etc.).
/// Methods with an <see cref="IServiceProvider"/> parameter support dependency injection.
/// </para>
/// <para>
/// This attribute is compatible with Native AOT when used with <see cref="AgentClassSkill{TSelf}"/>.
/// Alternatively, override the <see cref="AgentSkill.Scripts"/> property and use
/// <see cref="AgentClassSkill{TSelf}.CreateScript"/> instead.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// public class MySkill : AgentClassSkill&lt;MySkill&gt;
/// {
/// public override AgentSkillFrontmatter Frontmatter { get; } = new("my-skill", "A skill.");
/// protected override string Instructions =&gt; "Use this skill to do something.";
///
/// [AgentSkillScript("do-something")]
/// [Description("Converts the input to upper case.")]
/// private static string DoSomething(string input) =&gt; input.ToUpperInvariant();
/// }
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
[Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public sealed class AgentSkillScriptAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="AgentSkillScriptAttribute"/> class.
/// The script name defaults to the method name.
/// </summary>
public AgentSkillScriptAttribute()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AgentSkillScriptAttribute"/> class
/// with an explicit script name.
/// </summary>
/// <param name="name">The script name used to identify this script.</param>
public AgentSkillScriptAttribute(string name)
{
this.Name = name;
}
/// <summary>
/// Gets the script name, or <see langword="null"/> to use the method name.
/// </summary>
public string? Name { get; }
}