diff --git a/src/equicordplugins/triviaAI/index.tsx b/src/equicordplugins/triviaAI/index.tsx
new file mode 100644
index 000000000..f4c860347
--- /dev/null
+++ b/src/equicordplugins/triviaAI/index.tsx
@@ -0,0 +1,66 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2026 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
+import { EquicordDevs } from "@utils/constants";
+import definePlugin, { IconComponent } from "@utils/types";
+import { Message } from "@vencord/discord-types";
+import { findExportedComponentLazy } from "@webpack";
+import { ChannelStore, Menu } from "@webpack/common";
+
+import { settings } from "./settings";
+import { getResponse, handleResponse, parseMessageContent } from "./utils";
+
+const RobotIconLazy = findExportedComponentLazy("RobotIcon");
+const RobotIcon: IconComponent = props => ;
+
+const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
+ const payload = parseMessageContent(message);
+ if (!payload) return;
+
+ const group = findGroupChildrenByChildId("copy-text", children);
+ if (!group) return;
+
+ group.splice(group.findIndex(c => c?.props?.id === "copy-text") + 1, 0, (
+
{
+ const ans = await getResponse(payload);
+ handleResponse(message, ans);
+ }}
+ />
+ ));
+};
+
+export default definePlugin({
+ name: "TriviaAI",
+ description: "A plugin that helps you answer trivia questions using AI.",
+ authors: [EquicordDevs.yash],
+ settings,
+ contextMenus: {
+ "message": messageCtxPatch
+ },
+ messagePopoverButton: {
+ icon: RobotIcon,
+ render(message: Message) {
+ const payload = parseMessageContent(message);
+ if (!payload) return null;
+
+ return {
+ label: "Answer With AI",
+ icon: RobotIcon,
+ message,
+ channel: ChannelStore.getChannel(message.channel_id),
+ onClick: async () => {
+ const ans = await getResponse(payload);
+ handleResponse(message, ans);
+ }
+ };
+ }
+ }
+});
diff --git a/src/equicordplugins/triviaAI/settings.ts b/src/equicordplugins/triviaAI/settings.ts
new file mode 100644
index 000000000..b4a97e823
--- /dev/null
+++ b/src/equicordplugins/triviaAI/settings.ts
@@ -0,0 +1,53 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2026 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { definePluginSettings } from "@api/Settings";
+import { OptionType } from "@utils/types";
+
+export const settings = definePluginSettings({
+ apiKey: {
+ type: OptionType.STRING,
+ description: "API Key.",
+ default: "",
+ placeholder: "Enter API Key here for your AI endpoint.",
+ componentProps: {
+ type: "password"
+ }
+ },
+ model: {
+ type: OptionType.STRING,
+ description: "AI Model to use.",
+ default: "google/gemini-3-flash-preview",
+ placeholder: "e.g. google/gemini-3-flash-preview, inception/mercury, openai/gpt-5.2-chat, etc."
+ },
+ systemPrompt: {
+ type: OptionType.STRING,
+ description: "System Prompt for the AI.",
+ default: "You are a helpful assistant who answers questions for the user in a concise and short way while using the least amount of words and punctuation.",
+ placeholder: "Enter system prompt."
+ },
+ maxTokens: {
+ type: OptionType.NUMBER,
+ description: "Maximum number of tokens in the response.",
+ default: 500
+ },
+ endpoint: {
+ type: OptionType.STRING,
+ description: "OpenAI Compatible AI Endpoint.",
+ default: "https://openrouter.ai/api/v1/chat/completions",
+ placeholder: "Enter your OpenAI compatible AI endpoint here."
+ },
+ autoRespond: {
+ type: OptionType.BOOLEAN,
+ description: "Automatically respond to messages on receiving a response.",
+ default: false
+ },
+ supportImages: {
+ type: OptionType.BOOLEAN,
+ description: "Pass images to the AI for context (if any). This is not supported by all models.",
+ default: true
+ }
+});
diff --git a/src/equicordplugins/triviaAI/utils.ts b/src/equicordplugins/triviaAI/utils.ts
new file mode 100644
index 000000000..501a14ffb
--- /dev/null
+++ b/src/equicordplugins/triviaAI/utils.ts
@@ -0,0 +1,188 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2026 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { insertTextIntoChatInputBox, sendMessage } from "@utils/discord";
+import { Logger } from "@utils/Logger";
+import { Message } from "@vencord/discord-types";
+import { showToast, Toasts } from "@webpack/common";
+
+import { settings } from "./settings";
+
+const logger = new Logger("TriviaAI");
+
+type TextPart = {
+ type: "text";
+ text: string;
+};
+
+type ImagePart = {
+ type: "image_url";
+ image_url: {
+ url: string;
+ detail?: "auto" | "high" | "low";
+ };
+};
+
+export type ContentPayload = string | (TextPart | ImagePart)[];
+
+export function parseMessageContent(message: Message): ContentPayload | null {
+ const textParts: string[] = [];
+
+ if (message.content && message.content.trim().length > 0) {
+ textParts.push(message.content);
+ }
+
+ message.embeds.forEach(embed => {
+ const embedBuffer: string[] = [];
+
+ const parts = [
+ embed.provider?.name ? `> ${embed.provider.name}` : null,
+ embed.author?.name ? `**${embed.author.name}**` : null,
+ embed.rawTitle ? `## ${embed.rawTitle}` : null,
+ embed.rawDescription ?? null,
+ ...(embed.fields?.map(f => (f.rawName && f.rawValue) ? `**${f.rawName}**: ${f.rawValue}` : null) ?? []),
+ embed.footer?.text ? `_${embed.footer.text}_` : null,
+ ];
+
+ parts.forEach(p => {
+ if (p) embedBuffer.push(p);
+ });
+
+ if (embedBuffer.length > 0) textParts.push(embedBuffer.join("\n"));
+ });
+
+ const combinedText = textParts.join("\n\n");
+
+ if (!settings.store.supportImages) {
+ return combinedText || null;
+ }
+
+ const imageUrls = new Set();
+
+ message.attachments
+ .filter(att => att.content_type?.startsWith("image/"))
+ .forEach(att => imageUrls.add(att.url));
+
+ message.embeds.forEach(embed => {
+ const potentialUrls = [
+ embed.image?.url,
+ embed.thumbnail?.url,
+ ...(embed.images?.map(img => img.url) ?? [])
+ ];
+
+ potentialUrls.forEach(url => {
+ if (url) imageUrls.add(url);
+ });
+ });
+
+ if (imageUrls.size === 0) {
+ return combinedText || null;
+ }
+
+ const payload: (TextPart | ImagePart)[] = [];
+
+ if (combinedText.length > 0) {
+ payload.push({
+ type: "text",
+ text: combinedText
+ });
+ }
+
+ imageUrls.forEach(url => {
+ payload.push({
+ type: "image_url",
+ image_url: { url }
+ });
+ });
+
+ return payload;
+}
+
+export async function handleResponse(message: Message, response: string): Promise {
+ if (settings.store.autoRespond) {
+ sendMessage(
+ message.channel_id,
+ { content: response },
+ true,
+ { messageReference: { channel_id: message.channel_id, message_id: message.id } }
+ );
+ return response;
+ } else {
+ insertTextIntoChatInputBox(response);
+ return response;
+ }
+}
+
+export async function getResponse(payload: ContentPayload): Promise {
+ if (!settings.store.apiKey) {
+ showToast("TriviaAI: API Key is not set.", Toasts.Type.FAILURE);
+ return "";
+ }
+
+ if (!settings.store.endpoint) {
+ showToast("TriviaAI: Endpoint is not set.", Toasts.Type.FAILURE);
+ return "";
+ }
+
+ if (!settings.store.model) {
+ showToast("TriviaAI: Model is not set.", Toasts.Type.FAILURE);
+ return "";
+ }
+
+ try {
+ const req = await fetch(settings.store.endpoint, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `Bearer ${settings.store.apiKey}`
+ },
+ body: JSON.stringify({
+ model: settings.store.model,
+ messages: [
+ {
+ role: "system",
+ content: settings.store.systemPrompt
+ },
+ {
+ role: "user",
+ content: payload
+ }
+ ],
+ max_tokens: settings.store.maxTokens,
+ })
+ });
+
+ if (!req.ok) {
+ const errorBody = await req.text();
+ const errorMessage = `API request failed with status ${req.status}: ${errorBody}`;
+ logger.error(errorMessage);
+ showToast(errorMessage, Toasts.Type.FAILURE);
+ return "";
+ }
+
+ const data = await req.json();
+
+ if (data.error) {
+ const errorMessage = data.error.message ?? "An unknown error occurred";
+ logger.error(`API Error: ${errorMessage}`);
+ showToast(errorMessage, Toasts.Type.FAILURE);
+ return "";
+ }
+
+ const response = data.choices[0].message.content;
+
+ if (!response?.trim()) {
+ logger.warn("no response from AI model");
+ return "";
+ }
+
+ return response;
+ } catch (e) {
+ logger.error("Error getting response from AI model", e);
+ showToast("Error getting response from AI model", Toasts.Type.FAILURE);
+ return "";
+ }
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 35ad0c963..4041fe3b8 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -1255,7 +1255,11 @@ export const EquicordDevs = Object.freeze({
davri: {
name: "Davri",
id: 457579346282938368n,
- }
+ },
+ yash: {
+ name: "yash",
+ id: 889150838658977874n,
+ },
} satisfies Record);
// iife so #__PURE__ works correctly