AIボット「Retry」が公開トピックで再生成ではなく重複返信を作成する

重大度

普通 — ただし、活発な公開トピックでは非常に迷惑になります:「再試行」をクリックし続けると、重複するボット投稿がトピックに氾濫し、メンバーからは「ボットが勝手に投稿している/ループに陥っている」と見なされます。

プラットフォーム

  • サーバー:Discourse コア main(2026.7.x 系)、最新の origin/maindbf5eedac40、2026-07-14)で再現。discourse-ai はコアにバンドルされています。
  • クライアント:複数のブラウザ/デバイス(デスクトップ版 Chrome、Android 版 Chrome、iOS Safari)で再現。サーバー側の問題であるため、クライアントは関係ありません。

説明

実際の結果: 公開トピックで、AI ボットの返信に対して再試行をクリックすると、トピックに全新的なボット投稿が追加されます。元の返信は変更されないため、再試行のたびに新しい投稿が追加されます。N 回の再試行 → N 件の余分な投稿。

期待される結果: 再試行は、AI ボットのPM / DM会話内で行われるのと同じように、既存のボット返信をその場で再生成(内容を置換)すべきです。新しい投稿は作成されません。

再現手順(クリーンな 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. 観察: 既存の投稿が再生成されるのではなく、新しいボット返信が追加されます。再試行を繰り返すと、毎回余分な投稿が 1 つずつ追加されます。
  5. 対照として、ボットとの PM内でも同じ操作を行います。PM 内では再試行は正しくその場で再生成され(重複なし)、PM と公開トピックの間のこの差異が問題を示しています。

公開トピックで 100% の確率で再現します。

根本原因(コードポインタ、現在の origin/main

  • BotController#retry_responseplugins/discourse-ai/app/controllers/discourse_ai/ai_bot/bot_controller.rb)は、**reply_post_id: post.id**を指定して Jobs::CreateAiReply をキューに投入します。つまり、「この既存の投稿を再生成せよ」という指示です。
  • Jobs::CreateAiReply はこれを reply_post として読み込み、Playground#reply_to(..., existing_reply_post: reply_post) に渡します。
  • Playground#reply_toplugins/discourse-ai/lib/ai_bot/playground.rb)内では:
    • stream_reply = post.topic.private_message? if stream_reply.nil? → 公開トピックでは false になります(~L518)。
    • existing_reply_postif stream_reply ブランチ内でのみ消費されます(reply_post = existing_reply_post、~L538)。
    • 非ストリーミングの else ブランチ(~L662)は、无条件に PostCreator.create!(...) を実行し、新しい投稿を追加し、再試行中の投稿には一切触れません。

したがって、PM 以外のトピックでは、retry_response からの「その場で再生成する」という意図は黙って破棄され、代わりに重複した投稿が作成されます。(この非対称性により、公開トピックのボット返信は非ストリーミングになりますが、これは既存の動作です。バグは、このパスで再試行の existing_reply_post が無視される点に特有です。)

提案される修正(方向性のみ)

ストリーミングに関係なく existing_reply_post を尊重します。例えば、非ストリーミングブランチで existing_reply_post が存在する場合は、PostCreator.create! を呼び出す代わりにそれを revise(修正)するか、「既存の投稿を再利用する」決定を stream_reply から切り離します。

セーフモード

該当なし — サーバー側のプラグイン動作であり、テーマやサイト JS に依存しません。

「いいね!」 1