// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
///
/// A skill defined entirely in code with resources (static values or delegates) and scripts (delegates).
///
///
/// All calls to ,
/// , and
/// must be made before the skill's is first called.
/// Calls made after that point will not be reflected in the generated
/// content. In typical usage, this means configuring all
/// resources and scripts before registering the skill with an
/// or .
///
[Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public sealed class AgentInlineSkill : AgentSkill
{
private readonly string _instructions;
private readonly JsonSerializerOptions? _serializerOptions;
private List? _resources;
private List? _scripts;
private string? _cachedContent;
///
/// Initializes a new instance of the class
/// with a pre-built .
///
/// The skill frontmatter containing name, description, and other metadata.
/// Skill instructions text.
///
/// Optional applied by default to all scripts and delegate resources
/// added to this skill. Individual and
/// calls can override this default. When , is used.
///
public AgentInlineSkill(AgentSkillFrontmatter frontmatter, string instructions, JsonSerializerOptions? serializerOptions = null)
{
this.Frontmatter = Throw.IfNull(frontmatter);
this._instructions = Throw.IfNullOrWhitespace(instructions);
this._serializerOptions = serializerOptions;
}
///
/// Initializes a new instance of the class
/// with all frontmatter properties specified individually.
///
/// Skill name in kebab-case.
/// Skill description for discovery.
/// Skill instructions text.
/// Optional license name or reference.
/// Optional compatibility information (max 500 chars).
/// Optional space-delimited list of pre-approved tools.
/// Optional arbitrary key-value metadata.
///
/// Optional applied by default to all scripts and delegate resources
/// added to this skill. Individual and
/// calls can override this default. When , is used.
///
public AgentInlineSkill(
string name,
string description,
string instructions,
string? license = null,
string? compatibility = null,
string? allowedTools = null,
AdditionalPropertiesDictionary? metadata = null,
JsonSerializerOptions? serializerOptions = null)
: this(
new AgentSkillFrontmatter(name, description, compatibility)
{
License = license,
AllowedTools = allowedTools,
Metadata = metadata,
},
instructions,
serializerOptions)
{
}
///
public override AgentSkillFrontmatter Frontmatter { get; }
///
public override ValueTask GetContentAsync(CancellationToken cancellationToken = default)
{
return new(this._cachedContent ??= AgentInlineSkillContentBuilder.Build(this.Frontmatter.Name, this.Frontmatter.Description, this._instructions, this._resources, this._scripts));
}
///
public override ValueTask GetResourceAsync(string name, CancellationToken cancellationToken = default)
{
var resource = this._resources?.FirstOrDefault(r => r.Name == name);
return new(resource);
}
///
public override ValueTask GetScriptAsync(string name, CancellationToken cancellationToken = default)
{
var script = this._scripts?.FirstOrDefault(s => s.Name == name);
return new(script);
}
///
/// Registers a static resource with this skill.
///
/// The resource name.
/// The static resource value.
/// An optional description of the resource.
/// This instance, for chaining.
public AgentInlineSkill AddResource(string name, object value, string? description = null)
{
(this._resources ??= []).Add(new AgentInlineSkillResource(name, value, description));
return this;
}
///
/// Registers a dynamic resource with this skill, backed by a C# delegate.
/// The delegate's parameters and return type are automatically marshaled via AIFunctionFactory.
///
/// The resource name.
/// A method that produces the resource value when requested.
/// An optional description of the resource.
///
/// Optional for this resource's delegate marshaling.
/// When , the skill-level default (if any) is used; otherwise is used.
///
/// This instance, for chaining.
public AgentInlineSkill AddResource(string name, Delegate method, string? description = null, JsonSerializerOptions? serializerOptions = null)
{
(this._resources ??= []).Add(new AgentInlineSkillResource(name, method, description, serializerOptions ?? this._serializerOptions));
return this;
}
///
/// Registers a script with this skill, backed by a C# delegate.
/// The delegate's parameters and return type are automatically marshaled via AIFunctionFactory.
///
/// The script name.
/// A method to execute when the script is invoked.
/// An optional description of the script.
///
/// Optional for this script's delegate marshaling.
/// When , the skill-level default (if any) is used; otherwise is used.
///
/// This instance, for chaining.
public AgentInlineSkill AddScript(string name, Delegate method, string? description = null, JsonSerializerOptions? serializerOptions = null)
{
(this._scripts ??= []).Add(new AgentInlineSkillScript(name, method, description, serializerOptions ?? this._serializerOptions));
return this;
}
}