/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ using Microsoft.Extensions.AI; namespace GitHub.Copilot; /// /// Provides helpers for defining Copilot tools. /// public static class CopilotTool { /// The key used in to indicate that a tool intentionally overrides a built-in Copilot tool with the same name. internal const string OverridesBuiltInToolKey = "is_override"; /// The key used in to indicate that a tool can execute without a permission prompt. internal const string SkipPermissionKey = "skip_permission"; /// /// Defines a tool for use in a . /// /// The delegate to invoke when the tool is called. /// The Microsoft.Extensions.AI options used to create the function. /// Copilot-specific tool options. /// An that can be added to . /// /// This is a helper on top of that applies additional configuration to support /// Copilot tools, such as binding a parameter and adding Copilot-specific metadata properties based on the provided /// . Any may be used as a Copilot tool; this helper simply provides additional conveniences /// for tools that opt in to advanced features. /// public static AIFunction DefineTool( Delegate method, CopilotToolOptions? toolOptions = null, AIFunctionFactoryOptions? factoryOptions = null) { ArgumentNullException.ThrowIfNull(method); factoryOptions ??= new(); ApplyToolOptions(factoryOptions, toolOptions); ApplyToolInvocationBinding(factoryOptions); return AIFunctionFactory.Create(method, factoryOptions); static void ApplyToolInvocationBinding(AIFunctionFactoryOptions factoryOptions) { var configureParameterBinding = factoryOptions.ConfigureParameterBinding; factoryOptions.ConfigureParameterBinding = pi => { var bindingOptions = configureParameterBinding?.Invoke(pi) ?? default; if (bindingOptions.BindParameter is null && !bindingOptions.ExcludeFromSchema && pi.ParameterType == typeof(ToolInvocation)) { return new AIFunctionFactoryOptions.ParameterBindingOptions { ExcludeFromSchema = true, BindParameter = static (pi, arguments) => { // CopilotClient/CopilotSession attach this context object before invoking the AIFunction. if (arguments.Context is not null && arguments.Context.TryGetValue(typeof(ToolInvocation), out var invocation) && invocation is ToolInvocation toolInvocation) { return toolInvocation; } if (pi.HasDefaultValue) { return null; } throw new InvalidOperationException($"No {nameof(ToolInvocation)} was provided for the tool call."); } }; } return bindingOptions; }; } static void ApplyToolOptions(AIFunctionFactoryOptions factoryOptions, CopilotToolOptions? toolOptions) { if (toolOptions is not null && (toolOptions.OverridesBuiltInTool || toolOptions.SkipPermission)) { Dictionary additionalProperties = new(StringComparer.Ordinal); if (factoryOptions.AdditionalProperties is not null) { foreach (var (key, value) in factoryOptions.AdditionalProperties) { additionalProperties[key] = value; } } if (toolOptions.OverridesBuiltInTool) { additionalProperties[OverridesBuiltInToolKey] = true; } if (toolOptions.SkipPermission) { additionalProperties[SkipPermissionKey] = true; } factoryOptions.AdditionalProperties = additionalProperties; } } } } /// /// Copilot-specific options for tools defined with . /// public sealed class CopilotToolOptions { /// /// Gets or sets a value indicating whether this tool intentionally overrides a built-in Copilot tool with the same name. /// /// /// When a with set to true is used to define a tool, /// the resulting will include "is_override": true in its . /// public bool OverridesBuiltInTool { get; set; } /// /// Gets or sets a value indicating whether this tool can execute without a permission prompt. /// /// /// When a with set to true is used to define a tool, /// the resulting will include "skip_permission": true in its . /// public bool SkipPermission { get; set; } }