重大度
普通 — ただし、活発な公開トピックでは非常に迷惑になります:「再試行」をクリックし続けると、重複するボット投稿がトピックに氾濫し、メンバーからは「ボットが勝手に投稿している/ループに陥っている」と見なされます。
プラットフォーム
- サーバー:Discourse コア
main(2026.7.x 系)、最新のorigin/main(dbf5eedac40、2026-07-14)で再現。discourse-aiはコアにバンドルされています。 - クライアント:複数のブラウザ/デバイス(デスクトップ版 Chrome、Android 版 Chrome、iOS Safari)で再現。サーバー側の問題であるため、クライアントは関係ありません。
説明
実際の結果: 公開トピックで、AI ボットの返信に対して再試行をクリックすると、トピックに全新的なボット投稿が追加されます。元の返信は変更されないため、再試行のたびに新しい投稿が追加されます。N 回の再試行 → N 件の余分な投稿。
期待される結果: 再試行は、AI ボットのPM / DM会話内で行われるのと同じように、既存のボット返信をその場で再生成(内容を置換)すべきです。新しい投稿は作成されません。
再現手順(クリーンな Discourse から)
- Discourse AI と AI ボットを有効化し、ボットユーザーを持つ AI エージェント(ペルソナ)を作成/有効化します。公開トピックで回答できるように「トピックメンションを許可」(
allow_topic_mentions)をオンにします。あなたのユーザーグループをエージェントの許可グループおよびai_bot_allowed_groupsに追加します。 - 公開トピックで、投稿内でボットを
@メンションして返信を促します。 - ボットの返信で、投稿管理/レンチメニューを開き、再試行(再生成アクション →
POST /discourse-ai/ai-bot/post/:post_id/retry)をクリックします。 - 観察: 既存の投稿が再生成されるのではなく、新しいボット返信が追加されます。再試行を繰り返すと、毎回余分な投稿が 1 つずつ追加されます。
- 対照として、ボットとの PM内でも同じ操作を行います。PM 内では再試行は正しくその場で再生成され(重複なし)、PM と公開トピックの間のこの差異が問題を示しています。
公開トピックで 100% の確率で再現します。
根本原因(コードポインタ、現在の origin/main)
BotController#retry_response(plugins/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_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!(...)を実行し、新しい投稿を追加し、再試行中の投稿には一切触れません。
したがって、PM 以外のトピックでは、retry_response からの「その場で再生成する」という意図は黙って破棄され、代わりに重複した投稿が作成されます。(この非対称性により、公開トピックのボット返信は非ストリーミングになりますが、これは既存の動作です。バグは、このパスで再試行の existing_reply_post が無視される点に特有です。)
提案される修正(方向性のみ)
ストリーミングに関係なく existing_reply_post を尊重します。例えば、非ストリーミングブランチで existing_reply_post が存在する場合は、PostCreator.create! を呼び出す代わりにそれを revise(修正)するか、「既存の投稿を再利用する」決定を stream_reply から切り離します。
セーフモード
該当なし — サーバー側のプラグイン動作であり、テーマやサイト JS に依存しません。