Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.
17 changes: 17 additions & 0 deletions assets/javascripts/discourse/components/post/ai-persona-flair.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Component from "@glimmer/component";
import { inject as controller } from "@ember/controller";
import { isGPTBot } from "../../lib/ai-bot-helper";

export default class AiPersonaFlair extends Component {
static shouldRender(args) {
return isGPTBot(args.post.user);
}

@controller("topic") topicController;

<template>
<span class="persona-flair">
{{this.topicController.model.ai_persona_name}}
</span>
</template>
}
18 changes: 18 additions & 0 deletions assets/javascripts/discourse/lib/ai-bot-helper.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { getOwnerWithFallback } from "discourse/lib/get-owner";
import Composer from "discourse/models/composer";
import { i18n } from "discourse-i18n";
import ShareFullTopicModal from "../components/modal/share-full-topic-modal";

const MAX_PERSONA_USER_ID = -1200;

let enabledChatBotIds;

export function isGPTBot(user) {
if (!user) {
return;
}

if (!enabledChatBotIds) {
const currentUser = getOwnerWithFallback(this).lookup(
"service:current-user"
);
enabledChatBotIds = currentUser.ai_enabled_chat_bots.map((bot) => bot.id);
}

return enabledChatBotIds.includes(user.id);
}

export function isPostFromAiBot(post, currentUser) {
return (
post.user_id <= MAX_PERSONA_USER_ID ||
Expand Down
39 changes: 24 additions & 15 deletions assets/javascripts/initializers/ai-bot-replies.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@ import { withSilencedDeprecations } from "discourse/lib/deprecated";
import { withPluginApi } from "discourse/lib/plugin-api";
import { registerWidgetShim } from "discourse/widgets/render-glimmer";
import AiBotHeaderIcon from "../discourse/components/ai-bot-header-icon";
import AiPersonaFlair from "../discourse/components/post/ai-persona-flair";
import AiCancelStreamingButton from "../discourse/components/post-menu/ai-cancel-streaming-button";
import AiDebugButton from "../discourse/components/post-menu/ai-debug-button";
import AiShareButton from "../discourse/components/post-menu/ai-share-button";
import {
isGPTBot,
isPostFromAiBot,
showShareConversationModal,
} from "../discourse/lib/ai-bot-helper";
import { streamPostText } from "../discourse/lib/ai-streamer/progress-handlers";

let enabledChatBotIds = [];
let allowDebug = false;

function isGPTBot(user) {
return user && enabledChatBotIds.includes(user.id);
}

function attachHeaderIcon(api) {
api.headerIcons.add("ai", AiBotHeaderIcon);
}
Expand Down Expand Up @@ -57,6 +54,14 @@ function initializeAIBotReplies(api) {
}

function initializePersonaDecorator(api) {
api.renderAfterWrapperOutlet("post-meta-data-poster-name", AiPersonaFlair);

withSilencedDeprecations("discourse.post-stream-widget-overrides", () =>
initializeWidgetPersonaDecorator(api)
);
}

function initializeWidgetPersonaDecorator(api) {
let topicController = null;
api.decorateWidget(`poster-name:after`, (dec) => {
if (!isGPTBot(dec.attrs.user)) {
Expand Down Expand Up @@ -98,7 +103,11 @@ function initializePauseButton(api) {
const silencedKey =
transformerRegistered && "discourse.post-menu-widget-overrides";

withSilencedDeprecations(silencedKey, () => initializePauseWidgetButton(api));
withSilencedDeprecations("discourse.post-stream-widget-overrides", () => {
withSilencedDeprecations(silencedKey, () =>
initializePauseWidgetButton(api)
);
});
}

function initializePauseWidgetButton(api) {
Expand Down Expand Up @@ -251,16 +260,16 @@ export default {
const user = container.lookup("service:current-user");

if (user?.ai_enabled_chat_bots) {
enabledChatBotIds = user.ai_enabled_chat_bots.map((bot) => bot.id);
allowDebug = user.can_debug_ai_bot_conversations;
withPluginApi("1.6.0", attachHeaderIcon);
withPluginApi("1.34.0", initializeAIBotReplies);
withPluginApi("1.6.0", initializePersonaDecorator);
withPluginApi("1.34.0", (api) => initializeDebugButton(api, container));
withPluginApi("1.34.0", (api) => initializeShareButton(api, container));
withPluginApi("1.22.0", (api) =>
initializeShareTopicButton(api, container)
);

withPluginApi((api) => {
attachHeaderIcon(api);
initializeAIBotReplies(api);
initializePersonaDecorator(api);
initializeDebugButton(api, container);
initializeShareButton(api, container);
initializeShareTopicButton(api, container);
});
}
},
};