grammyjs / conversations

Conversational interfaces for grammY.
https://grammy.dev/plugins/conversations
MIT License
51 stars 17 forks source link

Session value not persisting after conversation ends #116

Closed qvvvvq closed 2 months ago

qvvvvq commented 2 months ago

Hi, I'm encountering an issue with session persistence when using conversations in grammy. After modifying the session inside a conversation, the session reverts to its default values in the global middleware after the conversation ends. I expect the session to retain the modified values, but it seems to reset instead.

Here’s a simplified version of the code:

//  @ts-nocheck
import { Bot, session } from "grammy";
import { conversations, createConversation } from "@grammyjs/conversations";

const initialSession = () => ({
  value: "default",
});

export async function myConversation(conversation, ctx) {
  console.log("πŸš€ ~ ctx.session:myConversation:before", ctx.session);
  await ctx.reply("Please send a new value");

  const { message } = await conversation.waitFor("message:text");
  if (message) {
    ctx.session.value = message.text;
    console.log("πŸš€ ~ ctx.session:myConversation:after", ctx.session);
  }
}

export function logMiddleware(bot) {
  bot.use((ctx, next) => {
    console.log("πŸš€ ~ ctx.session:logMiddleware", ctx.session);
    return next();
  });
}

export async function setupBot() {
  const bot = new Bot("<token>");

  bot.use(session({ initial: initialSession }));
  bot.use(conversations());
  bot.use(createConversation(myConversation));

  logMiddleware(bot);

  bot.command("start", async (ctx) => {
    await ctx.reply("Hello! Use /change to start conversation.");
  });

  bot.command("change", async (ctx) => {
    await ctx.conversation.enter("myConversation");
  });

  bot.start();
}

The output I’m seeing:

πŸš€ ~ ctx.session:logMiddleware { value: 'default' }
πŸš€ ~ ctx.session:myConversation:before { value: 'default' }
πŸš€ ~ ctx.session:myConversation:after { value: 'new value' }
πŸš€ ~ ctx.session:logMiddleware { value: 'default' }

In the conversation, the session value updates correctly (ctx.session:myConversation:after shows the new value), but after the conversation completes, the global logMiddleware still shows the default session values.

Expected Behavior: The session should retain the updated values after the conversation ends.

Actual Behavior: The session resets to the default values in the global middleware after the conversation finishes.

Am I missing something about how session updates are handled after conversations, or is this a potential issue?

Thank you for your help!

KnorpelSenf commented 2 months ago

This is a known problem with sessions in conversations. What happens is essentially that you're modifying an old context object that has already written back its session data. What's why modifying it has no effect.

There is conversation.session which you should use instead. It selects the current context object and thus makes sure the data is persisted.

This is documented here: https://grammy.dev/plugins/conversations#rule-iii-use-convenience-functions