d4n3436/Fergun.Interactive

InteractiveService throws for no reason when using DeferredUpdateMessage.

Closed this issue · 7 comments

The interactionType that uses a call to ModifyOriginalResponseAsync (DeferredUpdateMessage) throws an ArgumentException for an unknown reason in InteractiveService.SendOrModifyMessageAsync for slash commands. Unlike the exception suggests, ModifyOriginalResponseAsync can be used in slash commands.

The only alternative is using GetOriginalResponseAsync and passing that in, which, depending on the permissions/context the bot is in, Discord complains about and it doesn't work. (Discord is more picky about messages being edited in that way)

Can you please send a stack trace and sample code?

using Discord.Interactions;
using Fergun.Interactive;
using Fergun.Interactive.Pagination;

namespace Asahi.Modules;

public class TestModule(InteractiveService interactive) : BotModule
{
    [SlashCommand("test", "hello!")]
    public async Task TestSlash()
    {
        await DeferAsync();

        var paginator = new StaticPaginatorBuilder()
            .WithPages([new PageBuilder().WithText("hello!")])
            .WithDefaultEmotes();

        await interactive.SendPaginatorAsync(paginator.Build(), Context.Interaction, TimeSpan.FromMinutes(1),
            InteractionResponseType.DeferredUpdateMessage);
    }
}
System.ArgumentException: Interaction response type DeferredUpdateMessage can only be used on component interactions. (Parameter 'responseType')
   at Fergun.Interactive.InteractiveGuards.ValidResponseType(InteractionResponseType responseType, IDiscordInteraction interaction, String parameterName)
   at Fergun.Interactive.InteractiveService.SendOrModifyMessageAsync[TOption](IInteractiveElement`1 element, IDiscordInteraction interaction, InteractionResponseType responseType, Boolean ephemeral)
   at Fergun.Interactive.InteractiveService.SendPaginatorAsync(Paginator paginator, IDiscordInteraction interaction, Nullable`1 timeout, InteractionResponseType responseType, Boolean ephemeral, Action`1 messageAction, Boolean resetTimeoutOnInput, CancellationToken cancellationToken)
   at Asahi.Modules.TestModule.TestSlash()
   at Discord.Interactions.Builders.ModuleClassBuilder.<>c__DisplayClass11_0.<<CreateCallback>g__ExecuteCallback|1>d.MoveNext()

My problem here is InteractionResponseType.DeferredUpdateMessage is the only way to call FollowupAsync for a paginator, but that is blocked because of that exception

The value that is passed into responseType is either the response type the library should use or the one that was already used (for deferred interactions). The exception occurs because the library expects a component interaction when InteractionResponseType.DeferredUpdateMessage is passed (Discord says it's only valid for component interactions).

The response type that should be passed is InteractionResponseType.DeferredChannelMessageWithSource (the one DeferAsync() uses).

Apologies, sent this report at 4am my time and must've not been thinking haha

My problem here is InteractionResponseType.DeferredUpdateMessage is the only way to call FollowupAsync for a paginator, but that is blocked because of that exception

Meant to say ModifyOriginalResponseAsync here, not FollowupAsync 😅
This codeblock might illustrate what I mean a bit better?

using Discord.Interactions;
using Fergun.Interactive;
using Fergun.Interactive.Pagination;

namespace Asahi.Modules;

public class TestModule(InteractiveService interactive) : BotModule
{
    [SlashCommand("test", "hello!")]
    public async Task TestSlash()
    {
        await DeferAsync();

        await FollowupAsync("hi!");

        var paginator = new StaticPaginatorBuilder()
            .WithPages([new PageBuilder().WithText("hello!")])
            .WithDefaultEmotes();

        await interactive.SendPaginatorAsync(paginator.Build(), Context.Interaction, TimeSpan.FromMinutes(1),
            InteractionResponseType.DeferredUpdateMessage);
    }
}

I see. You need to get the return value of FollowupAsync() and pass it to the overload of SendPaginatorAsync() that accepts a message.
For ephemeral interactions, I don't think it's currently supported because modifying an ephemeral message without an interaction was not possible at the time I was writing the library/API, and it's not really common to defer and send a followup before sending a paginator.

iirc editing an interaction's message using the message edit stuff (passing in the return value of FollowupAsync) instead of ModifyOriginalResponseAsync causes issues in some situations because of the permissions that Discord grants. Think user apps are one of them? Ephemeral too, as you'd mentioned.
Either way, my stopgap is i'm using a temp fork of the repo with that check removed. Not ideal though as its not up-to-date

I've tried to use it in a user app and there seems to be a bug in Discord.Net (I get a NRE on ModifyAsync()) so I can't really test it.

Anyways, I've removed the restriction on InteractionResponseType.DeferredUpdateMessage and limited it to InteractionResponseType.UpdateMessage, which actually requires a component interaction. I'll release a new version soon.