diff --git a/routes/chat_routes.py b/routes/chat_routes.py
index a718d3fbe..9880522c8 100644
--- a/routes/chat_routes.py
+++ b/routes/chat_routes.py
@@ -452,7 +452,9 @@ def setup_chat_routes(
search_context = form_data.get("search_context") # pre-fetched web search results (compare mode)
compare_mode = str(form_data.get("compare_mode", "")).lower() == "true"
incognito = str(form_data.get("incognito", "")).lower() == "true"
- plan_mode = str(form_data.get("plan_mode", "")).lower() == "true"
+ # Plan mode is not part of the merge-ready UI. Ignore stale clients or
+ # manual form posts that still send plan_mode=true.
+ plan_mode = False
chat_mode = str(form_data.get("mode", "")).lower() # 'chat' or 'agent'
# Workspace: confine the agent's file/shell tools to this folder. Validate
# it's a real directory; ignore (no confinement) otherwise.
diff --git a/static/app.js b/static/app.js
index 8216d6485..20ef1f705 100644
--- a/static/app.js
+++ b/static/app.js
@@ -1555,7 +1555,6 @@ function initializeEventListeners() {
const MODE_TOOLS = [
{ btnId: 'web-toggle-btn', checkboxId: 'web-toggle', stateKey: 'web' },
{ btnId: 'bash-toggle-btn', checkboxId: 'bash-toggle', stateKey: 'bash' },
- { btnId: 'plan-toggle-btn', checkboxId: 'plan-toggle', stateKey: 'plan' },
];
function _modeKey(stateKey, mode) { return `${stateKey}_${mode}`; }
@@ -1564,9 +1563,6 @@ function initializeEventListeners() {
const state = loadToggleState();
const key = _modeKey(stateKey, mode);
if (Object.prototype.hasOwnProperty.call(state, key)) return !!state[key];
- // Plan mode is opt-in: never default it on, otherwise every agent turn
- // would be forced into planning.
- if (stateKey === 'plan') return false;
return mode === 'agent'; // default: ON in agent, OFF in chat
}
@@ -1579,7 +1575,6 @@ function initializeEventListeners() {
const TOOL_TOGGLE_TOAST_LABELS = {
web: 'Web search',
bash: 'Shell',
- plan: 'Plan mode',
};
function showToolToggleToast(stateKey, active) {
@@ -1592,8 +1587,8 @@ function initializeEventListeners() {
MODE_TOOLS.forEach(({ btnId, checkboxId, stateKey }) => {
const btn = el(btnId);
if (!btn) return;
- // Hide bash and plan buttons in chat mode
- if (mode === 'chat' && (stateKey === 'bash' || stateKey === 'plan')) {
+ // Hide bash button in chat mode
+ if (mode === 'chat' && stateKey === 'bash') {
btn.style.display = 'none';
return;
}
@@ -1614,12 +1609,10 @@ function initializeEventListeners() {
const state = loadToggleState();
let currentMode = state.mode || 'chat';
- // Immediately hide bash/plan buttons in chat mode on page load
+ // Immediately hide bash button in chat mode on page load
if (currentMode === 'chat') {
const bashBtn = el('bash-toggle-btn');
- const planBtn = el('plan-toggle-btn');
if (bashBtn) bashBtn.style.display = 'none';
- if (planBtn) planBtn.style.display = 'none';
}
function setMode(mode) {
@@ -1710,79 +1703,6 @@ function initializeEventListeners() {
setupToggle('web-toggle-btn', 'web-toggle', 'web');
setupToggle('bash-toggle-btn', 'bash-toggle', 'bash');
try { workspaceModule.initWorkspace(); } catch (_) {}
- setupToggle('plan-toggle-btn', 'plan-toggle', 'plan');
-
- // Set plan mode on/off directly (checkbox + button state + saved pref) WITHOUT
- // going through the button's click handler — used by the plan menu and by the
- // "Approve & Run" flow. Going through .click() would hit the plan-menu
- // intercept below (a stored plan re-opens the menu instead of toggling), which
- // is exactly the bug that left approved plans stuck in plan mode.
- function _setPlanMode(on) {
- const btn = el('plan-toggle-btn');
- const chk = el('plan-toggle');
- const mode = (loadToggleState().mode) || 'chat';
- if (chk) chk.checked = !!on;
- if (btn) { btn.classList.toggle('active', !!on); btn.setAttribute('aria-pressed', String(!!on)); }
- saveToolPref('plan', mode, !!on);
- }
- window._setPlanMode = _setPlanMode;
-
- // ── Plan-button menu ──
- // When a plan exists for this chat, clicking the plan button opens a small
- // menu (Show plan / Plan mode on-off) instead of plain-toggling — so the plan
- // window can be re-opened and docked at any time while the agent works. With
- // no plan, the button behaves as before (one-click toggle).
- (function initPlanMenu() {
- const planBtn = el('plan-toggle-btn');
- if (!planBtn) return;
- const _hasPlan = () => { try { return !!(window._getStoredPlan && window._getStoredPlan()); } catch (_) { return false; } };
- const _close = () => { const m = document.getElementById('plan-menu'); if (m) m.remove(); };
- function _open() {
- _close();
- const planChk = el('plan-toggle');
- const on = !!(planChk && planChk.checked);
- const menu = document.createElement('div');
- menu.id = 'plan-menu';
- menu.className = 'overflow-menu plan-menu';
- menu.innerHTML =
- ''
- + '';
- document.body.appendChild(menu);
- const r = planBtn.getBoundingClientRect();
- menu.style.position = 'fixed';
- menu.style.left = Math.round(r.left) + 'px';
- menu.style.top = Math.round(r.top - menu.offsetHeight - 6) + 'px';
- menu.querySelector('[data-act="show"]').addEventListener('click', () => {
- _close();
- const txt = window._getStoredPlan ? window._getStoredPlan() : '';
- if (txt && window.planWindowModule) window.planWindowModule.openPlanWindow(txt, null);
- });
- menu.querySelector('[data-act="toggle"]').addEventListener('click', () => {
- _close();
- _setPlanMode(!on); // flip state directly (no click → no menu re-open)
- });
- // Dismiss on any outside click (capture so it beats other handlers) / Escape.
- setTimeout(() => {
- const off = (e) => {
- if (!menu.contains(e.target) && e.target !== planBtn) {
- _close(); document.removeEventListener('click', off, true); document.removeEventListener('keydown', esc, true);
- }
- };
- const esc = (e) => { if (e.key === 'Escape') { _close(); document.removeEventListener('click', off, true); document.removeEventListener('keydown', esc, true); } };
- document.addEventListener('click', off, true);
- document.addEventListener('keydown', esc, true);
- }, 0);
- }
- planBtn.addEventListener('click', (e) => {
- // With a stored plan, the button opens the menu (Show plan / toggle).
- // Without one, it falls through to the normal one-click toggle.
- if (_hasPlan()) { e.preventDefault(); e.stopImmediatePropagation(); _open(); }
- }, true); // capture phase: intercept before setupToggle's bubble handler
- })();
try { workspaceModule.initWorkspace(); } catch (_) {}
diff --git a/static/index.html b/static/index.html
index 522129fe9..ec4af199f 100644
--- a/static/index.html
+++ b/static/index.html
@@ -1084,12 +1084,6 @@
-
-