// ==UserScript==
// @name Grok Model Patcher
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Patches grok.com POST requests to switch between grok-3 and grok-2 models
// @author GrokPatcher
// @match https://grok.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const generateId = () => Math.random().toString(16).slice(2);
const createMenu = () => {
const menu = document.createElement('div');
menu.id = 'grok-patcher-menu';
menu.style.cssText = `
position: fixed;
top: 10px;
left: 10px;
z-index: 10000;
background: #1f2937;
padding: 10px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
cursor: move;
user-select: none;
`;
menu.innerHTML = `
grok-3 Rate Limit: N/A
grok-2 Rate Limit: N/A
Donate
`;
document.body.appendChild(menu);
makeDraggable(menu);
return menu;
};
const makeDraggable = (element) => {
let dragging = false;
let xOffset = 0;
let yOffset = 0;
element.addEventListener('mousedown', (e) => {
dragging = true;
xOffset = e.clientX - parseInt(element.style.left || '10');
yOffset = e.clientY - parseInt(element.style.top || '10');
});
document.addEventListener('mousemove', (e) => {
if (dragging) {
element.style.left = `${e.clientX - xOffset}px`;
element.style.top = `${e.clientY - yOffset}px`;
}
});
document.addEventListener('mouseup', () => {
dragging = false;
});
};
const updateRateLimits = (limits) => {
const grok3Elem = document.getElementById('rate_limit_grok3');
const grok2Elem = document.getElementById('rate_limit_grok2');
grok3Elem.textContent = limits?.['grok-3']
? `grok-3 Rate Limit: ${limits['grok-3'].remainingQueries}/${limits['grok-3'].totalQueries}`
: 'grok-3 Rate Limit: N/A';
grok2Elem.textContent = limits?.['grok-2']
? `grok-2 Rate Limit: ${limits['grok-2'].remainingQueries}/${limits['grok-2'].totalQueries}`
: 'grok-2 Rate Limit: N/A';
};
const fetchRateLimits = async () => {
try {
const models = ['grok-3', 'grok-2'];
const limits = {};
for (const model of models) {
const response = await fetch('https://grok.com/rest/rate-limits', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Xai-Request-Id': generateId(),
'Accept-Language': 'en-US,en;q=0.9',
'User-Agent': navigator.userAgent,
'Accept': '*/*',
'Origin': 'https://grok.com',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
'Referer': 'https://grok.com/',
'Accept-Encoding': 'gzip, deflate, br',
'Priority': 'u=1, i'
},
body: JSON.stringify({ requestKind: 'DEFAULT', modelName: model })
});
if (!response.ok) throw new Error(`Failed to fetch ${model} rate limits`);
limits[model] = await response.json();
}
updateRateLimits(limits);
return limits;
} catch (error) {
updateRateLimits(null);
alert('Failed to fetch rate limits. Please try again later.');
}
};
const startRateLimitRefresh = () => {
fetchRateLimits();
setInterval(fetchRateLimits, 30000);
};
const createPatcher = () => {
const originalFetch = window.fetch;
const originalXhrOpen = XMLHttpRequest.prototype.open;
const originalXhrSend = XMLHttpRequest.prototype.send;
let grok2Active = false;
const isTargetUrl = (url) => {
return (url.includes('/rest/app-chat/conversations/') && url.endsWith('/responses')) ||
url === 'https://grok.com/rest/app-chat/conversations/new';
};
const patchFetch = async (input, init) => {
if (grok2Active && init?.method === 'POST' && typeof input === 'string' && isTargetUrl(input)) {
try {
const payload = JSON.parse(init.body);
payload.modelName = 'grok-2';
init.body = JSON.stringify(payload);
} catch (error) {
alert('Failed to patch fetch request.');
}
}
return originalFetch(input, init);
};
const patchXhrOpen = function(method, url) {
this._url = url;
this._method = method;
return originalXhrOpen.apply(this, arguments);
};
const patchXhrSend = function(body) {
if (grok2Active && this._method === 'POST' && isTargetUrl(this._url)) {
try {
const payload = JSON.parse(body);
payload.modelName = 'grok-2';
body = JSON.stringify(payload);
} catch (error) {
alert('Failed to patch XHR request.');
}
}
return originalXhrSend.call(this, body);
};
return {
enable: async () => {
grok2Active = true;
window.fetch = patchFetch;
XMLHttpRequest.prototype.open = patchXhrOpen;
XMLHttpRequest.prototype.send = patchXhrSend;
await fetchRateLimits();
},
disable: async () => {
grok2Active = false;
window.fetch = originalFetch;
XMLHttpRequest.prototype.open = originalXhrOpen;
XMLHttpRequest.prototype.send = originalXhrSend;
await fetchRateLimits();
},
isActive: () => grok2Active
};
};
const init = () => {
const tailwind = document.createElement('script');
tailwind.src = 'https://cdn.tailwindcss.com';
tailwind.onerror = () => alert('Failed to load TailwindCSS. Some styles may not work.');
document.head.appendChild(tailwind);
const menu = createMenu();
const patcher = createPatcher();
tailwind.onload = () => {
const toggleButton = document.getElementById('toggle_model');
const donationLink = document.getElementById('donation_link');
toggleButton.addEventListener('click', async () => {
try {
if (patcher.isActive()) {
await patcher.disable();
toggleButton.textContent = 'Using grok-3';
toggleButton.classList.replace('bg-red-600', 'bg-blue-600');
toggleButton.classList.replace('hover:bg-red-700', 'hover:bg-blue-700');
} else {
await patcher.enable();
toggleButton.textContent = 'Using grok-2';
toggleButton.classList.replace('bg-blue-600', 'bg-red-600');
toggleButton.classList.replace('hover:bg-blue-700', 'hover:bg-red-700');
}
} catch (error) {
alert('Failed to toggle model. Please try again.');
}
});
donationLink.addEventListener('click', (e) => {
e.preventDefault();
const walletPage = window.open('', '_blank');
walletPage.document.write(`
Donation Wallets
Donate to Support Us
Send donations to these wallet addresses:
- Bitcoin:
bc1q7crku5553xc32fqr4mhugu8jneeuywy4rn5eny
- Ethereum:
0x634F663F87DBC3C2938aA95fC6C0eE53CA1bB6a3
- Monero:
42nARSjJfk3MWXERnZ7on3DDowKVDn6sC3b35XRtSJM1SSpVN34CC7x5jcMeBeacMrEHuDo24kh1HaYq5BPpG1Fo3UeZtAL
`);
walletPage.document.close();
});
startRateLimitRefresh();
};
};
init();
})();