Бот AI «Retry» создает дублирующий ответ вместо регенерации в публичных (не ЛС) темах

Серьезность

Обычная — но вызывает высокий уровень раздражения в загруженных публичных темах: многократные нажатия кнопки «Повторить» засыпают тему дубликатами сообщений бота, из-за чего пользователям кажется, что бот «отправляет сообщения сам по себе / застрял в цикле».

Платформа

  • Сервер: Discourse core main (ветка 2026.7.x), воспроизведено на последней версии origin/main (dbf5eedac40, 14.07.2026). discourse-ai включен в ядро.
  • Клиент: воспроизведено в различных браузерах/на устройствах (Chrome на десктопе, Chrome на Android, Safari на iOS) — проблема находится на стороне сервера, поэтому клиент не имеет значения.

Описание

Фактический результат: В публичной теме нажатие кнопки Повторить на ответе AI-бота добавляет совершенно новое сообщение бота в тему. Исходный ответ остается нетронутым, поэтому каждое нажатие «Повторить» добавляет еще одно сообщение. N повторений → N дополнительных сообщений.

Ожидаемый результат: Кнопка «Повторить» должна пересоздавать существующий ответ бота на месте (заменять его содержимое), так же, как это происходит в личных сообщениях (PM/DM) с AI-ботом. Новое сообщение создаваться не должно.

Шаги для воспроизведения (на чистой установке Discourse)

  1. Включите Discourse AI + AI-бота; создайте/включите AI агента (персона) с пользователем-ботом и включите опцию «Разрешить упоминания в темах», чтобы он мог отвечать в публичных темах (allow_topic_mentions). Добавьте группу вашего пользователя в список разрешенных групп агента и в ai_bot_allowed_groups.
  2. В публичной теме сделайте @упоминание бота в сообщении, чтобы он ответил.
  3. В ответе бота откройте меню администратора/настроек сообщения (значок гаечного ключа) и нажмите Повторить (действие регенерации → POST /discourse-ai/ai-bot/post/:post_id/retry).
  4. Наблюдение: вместо регенерации существующего ответа добавляется новый ответ бота. Повторите нажатие «Повторить» → каждый раз добавляется одно лишнее сообщение.
  5. Для сравнения выполните то же самое в личном сообщении с ботом: «Повторить» корректно регенерирует ответ на месте (без дубликатов). Разница между поведением в личных сообщениях и публичных темах является ключевым признаком проблемы.

Проблема воспроизводится в 100% случаев в публичных темах.

Причина (указатели на код, текущий origin/main)

  • BotController#retry_response (plugins/discourse-ai/app/controllers/discourse_ai/ai_bot/bot_controller.rb) ставит в очередь Jobs::CreateAiReply с параметром reply_post_id: post.id — т.е. «пересоздать это существующее сообщение».
  • Jobs::CreateAiReply загружает его как reply_post и передает в Playground#reply_to(..., existing_reply_post: reply_post).
  • В Playground#reply_to (plugins/discourse-ai/lib/ai_bot/playground.rb):
    • stream_reply = post.topic.private_message? if stream_reply.nil?false для публичных тем (~L518).
    • existing_reply_post используется только внутри ветви if stream_reply (reply_post = existing_reply_post, ~L538).
    • Нестриминговая ветвь else (~L662) безоговорочно вызывает PostCreator.create!(...), добавляя новое сообщение и никогда не затрагивая сообщение, которое должно быть пересоздано.

Таким образом, для любой непубличной темы намерение «пересоздать на месте» из retry_response тихо игнорируется, и вместо этого создается дубликат. (Та же асимметрия означает, что ответы бота в публичных темах не используют стриминг, что является существующим поведением; ошибка заключается именно в том, что existing_reply_post игнорируется на этом пути.)

Предлагаемое исправление (общее направление)

Учитывать existing_reply_post независимо от использования стриминга — например, в нестриминговой ветви, если existing_reply_post присутствует, использовать метод revise вместо вызова PostCreator.create!; или разделить решение об «использовании существующего сообщения» от флага stream_reply.

Безопасный режим

Не применимо — поведение серверной части плагина, не зависит от тем/JS сайта.

1 лайк