Skip to content

Instantly share code, notes, and snippets.

@OXDBXKXO
Last active March 20, 2026 15:57
Show Gist options
  • Select an option

  • Save OXDBXKXO/44116e8bf9158c02f4326505aa4706d7 to your computer and use it in GitHub Desktop.

Select an option

Save OXDBXKXO/44116e8bf9158c02f4326505aa4706d7 to your computer and use it in GitHub Desktop.
[Tamper Monkey] Select Reasoning automatically on Mammouth AI
// ==UserScript==
// @name Mammouth AI - Reasoning by default
// @namespace https://github.com/OXDBXKXO
// @version 2026-03-20
// @description Automatically select Reasoning option in Mammouth AI
// @author OXDBXKXO
// @match https://mammouth.ai/app/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=mammouth.ai
// @grant none
// ==/UserScript==
(function() {
'use strict';
const DESIRED_OPTION = 'Reasoning';
const KNOWN_MODES = ['Auto', 'Reasoning', 'Text models', 'Web search'];
const NEW_CONVERSATION_PATH = '/app/a/default';
const TIMEOUT_MS = 5000;
const NAV_DELAY_MS = 50;
let lastUrl = location.href;
let running = false;
function isNewConversation(url = location.href) {
return new URL(url).pathname.endsWith(NEW_CONVERSATION_PATH);
}
function findModeTrigger() {
const buttons = document.querySelectorAll('button[aria-haspopup="menu"][id^="reka-dropdown-menu-trigger-v-"]');
for (const btn of buttons) {
const span = btn.querySelector('span');
if (span && KNOWN_MODES.includes(span.textContent.trim())) {
return btn;
}
}
return null;
}
function waitFor(findFn, timeout = TIMEOUT_MS) {
return new Promise((resolve, reject) => {
const el = findFn();
if (el) return resolve(el);
const obs = new MutationObserver(() => {
const el = findFn();
if (el) { obs.disconnect(); resolve(el); }
});
obs.observe(document.body, { childList: true, subtree: true });
setTimeout(() => { obs.disconnect(); reject(new Error('Timeout')); }, timeout);
});
}
function findOptionSpan(text) {
const spans = document.querySelectorAll('[data-reka-popper-content-wrapper] button[role="menuitem"] span');
for (const span of spans) {
if (span.textContent.trim() === text) return span;
}
return null;
}
async function main() {
if (running || !isNewConversation()) return;
running = true;
try {
const triggerBtn = await waitFor(findModeTrigger);
if (triggerBtn.querySelector('span')?.textContent.trim() === DESIRED_OPTION) {
console.log(`[TM] Already set to ${DESIRED_OPTION}, skipping`);
return;
}
triggerBtn.click();
console.log('[TM] Dropdown opened');
const span = await waitFor(() => findOptionSpan(DESIRED_OPTION));
for (const type of ['pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click']) {
span.dispatchEvent(new PointerEvent(type, { bubbles: true, cancelable: true }));
}
console.log(`[TM] Selected: ${DESIRED_OPTION}`);
} catch (err) {
console.error('[TM]', err.message);
} finally {
running = false;
}
}
function onUrlChange() {
const currentUrl = location.href;
if (currentUrl !== lastUrl) {
lastUrl = currentUrl;
if (isNewConversation(currentUrl)) {
console.log('[TM] New conversation detected');
setTimeout(main, NAV_DELAY_MS);
}
}
}
const origPushState = history.pushState;
history.pushState = function(...args) {
origPushState.apply(this, args);
onUrlChange();
};
const origReplaceState = history.replaceState;
history.replaceState = function(...args) {
origReplaceState.apply(this, args);
onUrlChange();
};
window.addEventListener('popstate', onUrlChange);
setInterval(onUrlChange, 1000);
main();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment