Skip to content
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

.Net: Missing CancellationToken in InvokePromptAsync<T>(...) #4573

Closed
TaffarelJr opened this issue Jan 10, 2024 · 8 comments · Fixed by #4584
Closed

.Net: Missing CancellationToken in InvokePromptAsync<T>(...) #4573

TaffarelJr opened this issue Jan 10, 2024 · 8 comments · Fixed by #4584
Assignees
Labels
.NET Issue or Pull requests regarding .NET code

Comments

@TaffarelJr
Copy link

Describe the bug
In Semantic Kernel 1.0.1, KernelExtensions.InvokePromptAsync<T>(...) doesn't include a CancellationToken parameter.

To Reproduce
N/A

Expected behavior
Async methods should allow a CancellationToken to be passed in. The other extensions in this class do; it looks like this one was forgotten.

@mehrandvd
Copy link
Contributor

I’m eager to take on this issue and make my first contribution to SK.

@stephentoub
Copy link
Member

Ugh, that's an oversight, it should have had one.

@matthewbolanos, @markwallace-microsoft, here's a small test of our non-breaking-change will: it's a binary breaking change to add a CancellationToken argument to the existing method, even as an optional parameter (it's not source breaking because existing callers would successfully recompile and just get the optional default value, but existing binaries calling the old method would start getting MethodNotFoundExceptions when targeting a newer version that only includes the new signature). So the right answer if we do care about that, which I think we do, is to add a new overload, even though it looks inconsistent.

And adding new overloads of methods with optional parameters is a little tricky, because if you just add another identical method but with an extra optional parameter, it's source breaking because existing callers will start to get ambiguity errors, with the compiler not knowing which method to pick if there's not an exact match (i.e. if you were passing all arguments). The answer is basically change the existing method to not have any optional arguments (removing the default value from all parameters), and then add a new overload with everything that was optional still optional plus the new optional method.

@bartonjs, do we have the canonical steps for this written down somewhere?

@markwallace-microsoft markwallace-microsoft added .NET Issue or Pull requests regarding .NET code and removed triage labels Jan 11, 2024
@github-actions github-actions bot changed the title Missing CancellationToken in InvokePromptAsync<T>(...) .Net: Missing CancellationToken in InvokePromptAsync<T>(...) Jan 11, 2024
@markwallace-microsoft markwallace-microsoft self-assigned this Jan 11, 2024
@markwallace-microsoft markwallace-microsoft moved this to Community PRs in Semantic Kernel Jan 11, 2024
@markwallace-microsoft
Copy link
Member

@mehrandvd We would be very happy for you to take this. Please link your PR to this issue and I'll look out for it. Thanks.

@mehrandvd
Copy link
Contributor

@stephentoub As I understood, this task is not simply adding a cancellationToken to InvokePromptAsync (avoiding a binary breaking change)
Instead, I should change the existing method to not have any optional arguments like:

public static Task<T?> InvokePromptAsync<T>(
    this Kernel kernel,
    string promptTemplate,
    KernelArguments? arguments,
    string? templateFormat,
    IPromptTemplateFactory? promptTemplateFactory)

and then add a new overload with everything optional still optional plus the new optional method like:

public static Task<T?> InvokePromptAsync<T>(
    this Kernel kernel,
    string promptTemplate,
    KernelArguments? arguments = null,
    string? templateFormat = null,
    IPromptTemplateFactory? promptTemplateFactory = null,
    CancellationToken cancellationToken = default)

Am I right?

@stephentoub
Copy link
Member

That's correct, with the existing method then delegating to the new one that has the implementation.

@bartonjs
Copy link
Member

bartonjs commented Jan 11, 2024

@bartonjs, do we have the canonical steps for this written down somewhere?

Framework Design Guidelines 3rd edition, section 5.1.1, p147 in the print edition, under: "DO move all default parameters to the new, longer overload when adding optional parameters to an existing method."

But I think y'all have the gist here; the only thing missing is to consider adding [EditorBrowsable(EditorBrowsableState.Never)] to the older overload if you want to reduce intellisense complexity.

With all of our guidelines stacked up, I'd expect

public static Task<T?> InvokePromptAsync<T>(
    this Kernel kernel,
    string promptTemplate,
    CancellationToken cancellationToken = default)
{
    // feel free to specify them all, but this's enough to latch to the final one.
    return InvokePromptAsync(kernel, promptTemplate, arguments: default, cancellationToken: cancellationToken);
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<T?> InvokePromptAsync<T>(
    this Kernel kernel,
    string promptTemplate,
    KernelArguments? arguments,
    string? templateFormat,
    IPromptTemplateFactory? promptTemplateFactory)
{
    return InvokePromptAsync(
        kernel,
        promptTemplate,
        arguments,
        templateFormat,
        promptTemplateFactory,
        default(CancellationToken));
}

public static Task<T?> InvokePromptAsync<T>(
    this Kernel kernel,
    string promptTemplate,
    KernelArguments? arguments = null,
    string? templateFormat = null,
    IPromptTemplateFactory? promptTemplateFactory = null,
    CancellationToken cancellationToken = default) { ... }

and if there was already a (kernel, promptTemplate) overload for it to also get EB-Never'd in favor of the (kernel, promptTemplate, cancellationToken) one.

@mehrandvd
Copy link
Contributor

@bartonjs Just to confirm, since there isn't a (kernel, promptTemplate) overload at the moment, the last two implementations should do the trick, right?

@bartonjs
Copy link
Member

The first one comes from

DO provide a simple overload, with no default parameters, for any
method with two or more defaulted parameters.

combined with the guidance to always default a CancellationToken.

It's not important for the "how do I add a new defaulted parameter without making a breaking change?" question, but it's something that "should" be there in the end.

@markwallace-microsoft markwallace-microsoft moved this from Community PRs to Sprint: In Review in Semantic Kernel Jan 15, 2024
github-merge-queue bot pushed a commit that referenced this issue Jan 15, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
…4584)

### Motivation and Context

KernelExtensions.InvokePromptAsync<T>(...) doesn't include a
CancellationToken parameter mistakenly as described in #4573

Closes #4573 

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

### Description

As @stephentoub mentioned in #4573, adding just a `cancellationToken`
causes a _binary breaking change_.
So, this method has two overloads, one with full optional parameters,
and a second overload with no optional parameters at all.

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

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

- [x] The code builds clean without any errors or warnings
- [x] 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
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄
@github-project-automation github-project-automation bot moved this from Sprint: In Review to Sprint: Done in Semantic Kernel Jan 15, 2024
Bryan-Roe pushed a commit to Bryan-Roe-ai/semantic-kernel that referenced this issue Oct 6, 2024
…ft#4573) (microsoft#4584)

### Motivation and Context

KernelExtensions.InvokePromptAsync<T>(...) doesn't include a
CancellationToken parameter mistakenly as described in microsoft#4573

Closes microsoft#4573 

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

### Description

As @stephentoub mentioned in microsoft#4573, adding just a `cancellationToken`
causes a _binary breaking change_.
So, this method has two overloads, one with full optional parameters,
and a second overload with no optional parameters at all.

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

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

- [x] The code builds clean without any errors or warnings
- [x] 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
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
.NET Issue or Pull requests regarding .NET code
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

6 participants