feat: make reasoning tab cycling opt-in (default off) (#1175)

This commit is contained in:
Devansh Jain
2026-02-26 15:42:52 -08:00
committed by GitHub
parent d184bd8aef
commit 6967f9dcc9
7 changed files with 203 additions and 1 deletions

View File

@@ -231,6 +231,7 @@ import {
buildQueuedUserText,
getQueuedNotificationSummaries,
} from "./helpers/queuedMessageParts";
import { resolveReasoningTabToggleCommand } from "./helpers/reasoningTabToggle";
import { safeJsonParseOr } from "./helpers/safeJsonParse";
import { getDeviceType, getLocalTime } from "./helpers/sessionContext";
import {
@@ -479,6 +480,7 @@ const NON_STATE_COMMANDS = new Set([
"/export",
"/download",
"/statusline",
"/reasoning-tab",
]);
// Check if a command is interactive (opens overlay, should not be queued)
@@ -925,6 +927,7 @@ export default function App({
messageHistory = [],
resumedExistingConversation = false,
tokenStreaming = false,
reasoningTabCycleEnabled: initialReasoningTabCycleEnabled = false,
showCompactions = false,
agentProvenance = null,
releaseNotes = null,
@@ -945,6 +948,7 @@ export default function App({
messageHistory?: Message[];
resumedExistingConversation?: boolean; // True if we explicitly resumed via --resume
tokenStreaming?: boolean;
reasoningTabCycleEnabled?: boolean;
showCompactions?: boolean;
agentProvenance?: AgentProvenance | null;
releaseNotes?: string | null; // Markdown release notes to display above header
@@ -1484,6 +1488,11 @@ export default function App({
const [tokenStreamingEnabled, setTokenStreamingEnabled] =
useState(tokenStreaming);
// Reasoning tier Tab cycling preference (opt-in only, persisted globally)
const [reasoningTabCycleEnabled, setReasoningTabCycleEnabled] = useState(
initialReasoningTabCycleEnabled,
);
// Show compaction messages preference (can be toggled at runtime)
const [showCompactionsEnabled, _setShowCompactionsEnabled] =
useState(showCompactions);
@@ -7348,6 +7357,52 @@ export default function App({
return { submitted: true };
}
// Special handling for /reasoning-tab command - opt-in toggle for Tab tier cycling
if (
trimmed === "/reasoning-tab" ||
trimmed.startsWith("/reasoning-tab ")
) {
const resolution = resolveReasoningTabToggleCommand(
trimmed,
reasoningTabCycleEnabled,
);
if (!resolution) {
return { submitted: false };
}
const cmd = commandRunner.start(
trimmed,
"Updating reasoning Tab shortcut...",
);
setCommandRunning(true);
try {
if (resolution.kind === "status") {
cmd.finish(resolution.message, true);
return { submitted: true };
}
if (resolution.kind === "invalid") {
cmd.fail(resolution.message);
return { submitted: true };
}
setReasoningTabCycleEnabled(resolution.enabled);
settingsManager.updateSettings({
reasoningTabCycleEnabled: resolution.enabled,
});
cmd.finish(resolution.message, true);
} catch (error) {
const errorDetails = formatErrorDetails(error, agentId);
cmd.fail(`Failed: ${errorDetails}`);
} finally {
setCommandRunning(false);
}
return { submitted: true };
}
// Special handling for /new command - start new conversation
if (msg.trim() === "/new") {
const cmd = commandRunner.start(
@@ -12406,7 +12461,11 @@ Plan file path: ${planFilePath}`;
}
permissionMode={uiPermissionMode}
onPermissionModeChange={handlePermissionModeChange}
onCycleReasoningEffort={handleCycleReasoningEffort}
onCycleReasoningEffort={
reasoningTabCycleEnabled
? handleCycleReasoningEffort
: undefined
}
onExit={handleExit}
onInterrupt={handleInterrupt}
interruptRequested={interruptRequested}

View File

@@ -288,6 +288,15 @@ export const commands: Record<string, Command> = {
return "Managing status line...";
},
},
"/reasoning-tab": {
desc: "Toggle Tab shortcut for reasoning tiers (/reasoning-tab on|off|status)",
args: "[on|off|status]",
order: 36.6,
handler: () => {
// Handled specially in App.tsx
return "Managing reasoning Tab shortcut...";
},
},
"/terminal": {
desc: "Setup terminal shortcuts [--revert]",
order: 37,

View File

@@ -0,0 +1,47 @@
export type ReasoningTabToggleResolution =
| { kind: "status"; message: string }
| { kind: "set"; enabled: boolean; message: string }
| { kind: "invalid"; message: string };
const ENABLE_ARGS = new Set(["on", "enable", "enabled", "true", "1"]);
const DISABLE_ARGS = new Set(["off", "disable", "disabled", "false", "0"]);
const USAGE = "Usage: /reasoning-tab [on|off|status] (default is off)";
export function resolveReasoningTabToggleCommand(
trimmedInput: string,
currentlyEnabled: boolean,
): ReasoningTabToggleResolution | null {
const trimmed = trimmedInput.trim();
if (trimmed !== "/reasoning-tab" && !trimmed.startsWith("/reasoning-tab ")) {
return null;
}
const rawArg = trimmed.slice("/reasoning-tab".length).trim().toLowerCase();
if (!rawArg || rawArg === "status") {
return {
kind: "status",
message: currentlyEnabled
? "Reasoning Tab shortcut is enabled. Tab now cycles reasoning tiers."
: "Reasoning Tab shortcut is disabled. Use /reasoning-tab on to enable it.",
};
}
if (ENABLE_ARGS.has(rawArg)) {
return {
kind: "set",
enabled: true,
message: "Reasoning Tab shortcut enabled.",
};
}
if (DISABLE_ARGS.has(rawArg)) {
return {
kind: "set",
enabled: false,
message: "Reasoning Tab shortcut disabled.",
};
}
return { kind: "invalid", message: USAGE };
}