Skip to content

.Net: Allow inputs to be injected into OpenAPI plugins #6605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
matthewbolanos opened this issue Jun 7, 2024 · 4 comments · Fixed by #9663
Closed

.Net: Allow inputs to be injected into OpenAPI plugins #6605

matthewbolanos opened this issue Jun 7, 2024 · 4 comments · Fixed by #9663
Assignees
Labels
Ignite Features planned for next Ignite conference .NET Issue or Pull requests regarding .NET code openapi Issues related to the OpenAPI function importer sk team issue A tag to denote issues that where created by the Semantic Kernel team (i.e., not the community)

Comments

@matthewbolanos
Copy link
Member

matthewbolanos commented Jun 7, 2024

With native functions, you can inject services that can provide additional information to plugins so the AI doesn't need to provide it.

For example, you may inject a UserContextService service that allows you to get the current user's ID so you can use it within the plugin without the LLM ever needing to know it and pass it in. This reduces token usage and simplifies the job of the AI.

Today, with OpenAPI plugins, this is not possible. This task is to resolve this gap.

@matthewbolanos matthewbolanos converted this from a draft issue Jun 7, 2024
@matthewbolanos
Copy link
Member Author

matthewbolanos commented Jun 7, 2024

Since OpenAPI specs are predominantly used for AI devs (Python) and app devs (C#) to work together. The "solution" to this should be serializable so it can be shared across languages. Perhaps using our template engines to inject inputs from other plugins

@markwallace-microsoft markwallace-microsoft added openapi Issues related to the OpenAPI function importer .NET Issue or Pull requests regarding .NET code and removed triage labels Jun 7, 2024
@github-actions github-actions bot changed the title Allow inputs to be injected into OpenAPI plugins .Net: Allow inputs to be injected into OpenAPI plugins Jun 7, 2024
@SergeyMenshykh SergeyMenshykh added the Ignite Features planned for next Ignite conference label Aug 29, 2024
@SergeyMenshykh
Copy link
Member

Added to the Ignite bucket but it needs more clarification before working on it.

@markwallace-microsoft markwallace-microsoft moved this to Sprint: Planned in Semantic Kernel Oct 7, 2024
@evchaki evchaki added the sk team issue A tag to denote issues that where created by the Semantic Kernel team (i.e., not the community) label Nov 5, 2024
@markwallace-microsoft
Copy link
Member

This can be solved by transforming the plugin and allowing additional parameters to be injected. I will create a Blog Post showing how to do this for any type of KernelPlugin.

github-merge-queue bot pushed a commit that referenced this issue Nov 12, 2024
### Motivation and Context

Closes #6605

### Description

Some minor enhancements to the sample to match content in the Blog Post

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [ ] The code builds clean without any errors or warnings
- [ ] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄
@github-project-automation github-project-automation bot moved this from Sprint: In Review to Sprint: Done in Semantic Kernel Nov 12, 2024
@joshbartley
Copy link

@markwallace-microsoft appreciate the original code. I modified it to remove magic strings so you can add in parameters that were removed without having to rely on them always being there.

var transformedPlugin = CreatePluginWithParameters(
    agentPlugin,
    (KernelParameterMetadata parameter) => parameter.ParameterType != typeof(IUser) ,
    (KernelFunctionMetadata function, KernelArguments arguments, IReadOnlyList<KernelParameterMetadata> originalParameter) => {
        var userParameter = originalParameter.Where(x => x.ParameterType == typeof(IUser)).FirstOrDefault();
        if (userParameter != null)
            arguments.Add(userParameter.Name, User);

    }
);
    public delegate bool IncludeKernelParameter(KernelParameterMetadata parameter);

    public delegate void UpdateKernelArguments(KernelFunctionMetadata function, KernelArguments arguments, IReadOnlyList<KernelParameterMetadata> originalParameter);

    /// <summary>
    /// Create a <see cref="KernelPlugin"/> instance from the provided instance where each function only includes
    /// permitted parameters. The <see cref="IncludeKernelParameter"/> delegate is called to determine whether or not
    /// parameter will be included. The <see cref="UpdateKernelArguments"/> delegate is called to update the arguments
    /// and allow additional values to be included.
    /// </summary>
    public static KernelPlugin CreatePluginWithParameters(KernelPlugin plugin, IncludeKernelParameter includeKernelParameter, UpdateKernelArguments updateKernelArguments)
    {
        List<KernelFunction>? functions = new();

        foreach (KernelFunction function in plugin)
        {
            functions.Add(CreateFunctionWithParameters(function, includeKernelParameter, updateKernelArguments));
        }

        return KernelPluginFactory.CreateFromFunctions(plugin.Name, plugin.Description, functions);
    }
     /// <summary>
/// Create a <see cref="KernelFunction"/> instance from the provided instance which only includes permitted parameters.
/// The function method will add additional argument values before calling the original function.
/// </summary>
private static KernelFunction CreateFunctionWithParameters(KernelFunction function, IncludeKernelParameter includeKernelParameter, UpdateKernelArguments updateKernelArguments)
{
    var originalParameters = function.Metadata.Parameters;

    var method = (Kernel kernel, KernelFunction currentFunction, KernelArguments arguments, CancellationToken cancellationToken) =>
    {
        updateKernelArguments(  currentFunction.Metadata, arguments, originalParameters);
        return function.InvokeAsync(kernel, arguments, cancellationToken);
    };

    var options = new KernelFunctionFromMethodOptions()
    {
        FunctionName = function.Name,
        Description = function.Description,
        Parameters = CreateParameterMetadataWithParameters(function.Metadata.Parameters, includeKernelParameter),
        ReturnParameter = function.Metadata.ReturnParameter,
    };

    return KernelFunctionFactory.CreateFromMethod(method, options);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ignite Features planned for next Ignite conference .NET Issue or Pull requests regarding .NET code openapi Issues related to the OpenAPI function importer sk team issue A tag to denote issues that where created by the Semantic Kernel team (i.e., not the community)
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

5 participants