refactor(agent-mode): remove "Enable Agent Mode" toggle

Agent Mode is always on now (still desktop-only, since it requires
subprocess support). Drop the persisted `agentMode.enabled` flag and
the master toggle from settings, make `isAgentModeEnabled()`
platform-only, and clean up the now-dead toggle-reactive wiring
(ribbon refresh, settings-driven command re-registration).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Zero Liu 2026-05-28 15:33:44 -07:00
parent 0a6046ff0a
commit e25dd9861c
No known key found for this signature in database
7 changed files with 24 additions and 67 deletions

View file

@ -1,7 +1,7 @@
import { type App, Platform } from "obsidian";
import type CopilotPlugin from "@/main";
import { logError } from "@/logger";
import { type CopilotSettings, getSettings, useSettingsValue } from "@/settings/model";
import { getSettings } from "@/settings/model";
import { backendRegistry, listBackendDescriptors } from "./backends/registry";
import { AgentChatPersistenceManager } from "./session/AgentChatPersistenceManager";
import { AgentModelPreloader } from "./session/AgentModelPreloader";
@ -51,17 +51,16 @@ export { SkillManager, SkillsSettings, useManagedSkills } from "./skills";
export type { Skill } from "./skills";
/**
* True when Agent Mode is enabled and the platform supports it. Agent Mode
* requires subprocess support, so this is always false on mobile regardless
* of the persisted `enabled` flag (which may have been synced from desktop).
* True when the platform supports Agent Mode. Agent Mode is always on, but
* requires subprocess support, so this is always false on mobile.
*/
export function isAgentModeEnabled(settings: CopilotSettings = getSettings()): boolean {
return !Platform.isMobile && !!settings.agentMode?.enabled;
export function isAgentModeEnabled(): boolean {
return !Platform.isMobile;
}
/** React hook variant — re-renders when the setting or platform-derived value changes. */
/** Hook variant for symmetry with other settings-derived hooks. */
export function useIsAgentModeEnabled(): boolean {
return isAgentModeEnabled(useSettingsValue());
return isAgentModeEnabled();
}
/**
@ -159,7 +158,7 @@ export function createAgentSessionManager(app: App, plugin: CopilotPlugin): Agen
}
const settings = getSettings();
if (!isAgentModeEnabled(settings)) return manager;
if (!isAgentModeEnabled()) return manager;
// Per-backend preload registration: each backend's status flips
// independently. The chat UI gates on the active backend's status; the
// picker reads every backend's status to render per-backend loading rows.

View file

@ -25,7 +25,6 @@ import { checkIsPlusUser } from "@/plusUtils";
import CopilotPlugin from "@/main";
import { shouldUseMiyo } from "@/miyo/miyoUtils";
import { getAllQAMarkdownContent } from "@/search/searchUtils";
import { CopilotSettings } from "@/settings/model";
import { NoteSelectedTextContext, WebSelectedTextContext } from "@/types/message";
import { ensureFolderExists, isSourceModeOn } from "@/utils";
import { Editor, MarkdownView, Notice, TFile } from "obsidian";
@ -88,11 +87,7 @@ function addCheckCommand(
});
}
export function registerCommands(
plugin: CopilotPlugin,
prev: CopilotSettings | undefined,
next: CopilotSettings
) {
export function registerCommands(plugin: CopilotPlugin) {
addEditorCommand(plugin, COMMAND_IDS.COUNT_WORD_AND_TOKENS_SELECTION, async (editor: Editor) => {
const selectedText = editor.getSelection();
const wordCount = selectedText.split(" ").length;
@ -128,9 +123,9 @@ export function registerCommands(
await plugin.newChat();
});
// Re-runs from the settings subscription in main.ts so toggling the
// master switch refreshes the command palette.
if (isAgentModeEnabled(next)) {
// Agent Mode is always on, but requires subprocess support — register the
// agent commands on desktop only.
if (isAgentModeEnabled()) {
addCommand(plugin, COMMAND_IDS.OPEN_AGENT_CHAT_WINDOW, () => {
void plugin.activateAgentView();
});

View file

@ -1023,7 +1023,6 @@ export const DEFAULT_SETTINGS: CopilotSettings = {
autoCompactThreshold: 128000,
convertedDocOutputFolder: DEFAULT_CONVERTED_DOC_OUTPUT_FOLDER,
agentMode: {
enabled: true,
byok: {},
mcpServers: [],
activeBackend: "opencode",

View file

@ -91,7 +91,6 @@ import {
Notice,
Platform,
Plugin,
setIcon,
TFile,
WorkspaceLeaf,
} from "obsidian";
@ -183,10 +182,6 @@ export default class CopilotPlugin extends Plugin {
logError("Failed to persist settings.", error);
new Notice("Copilot failed to save settings. Check logs and try again.");
}
registerCommands(this, prev, next);
if (prev && prev.agentMode?.enabled !== next.agentMode?.enabled) {
this.refreshRibbonIcon();
}
// Sign-in / sign-out (isPlusUser flip) or key rotation while signed in.
if (
prev?.isPlusUser !== next.isPlusUser ||
@ -289,7 +284,7 @@ export default class CopilotPlugin extends Plugin {
() => (this.canUseAgentView() ? this.activateAgentView() : this.activateView())
);
registerCommands(this, undefined, getSettings());
registerCommands(this);
// Tool initialization is now handled automatically in CopilotPlusChainRunner and AutonomousAgentChainRunner
@ -781,10 +776,6 @@ export default class CopilotPlugin extends Plugin {
new Notice("Agent Chat is not available on mobile.");
return null;
}
if (!isAgentModeEnabled()) {
new Notice("Enable Agent Mode in Copilot settings first.");
return null;
}
if (!this.agentSessionManager) {
new Notice("Agent Chat is not initialized.");
return null;
@ -796,16 +787,6 @@ export default class CopilotPlugin extends Plugin {
return !!this.agentSessionManager && isAgentModeEnabled();
}
private refreshRibbonIcon() {
if (!this.ribbonIconEl) return;
const agentReady = this.canUseAgentView();
const icon = agentReady ? "bot" : "message-square";
const tooltip = agentReady ? "Open Copilot Agent Chat" : "Open Copilot Chat";
setIcon(this.ribbonIconEl, icon);
this.ribbonIconEl.setAttribute("aria-label", tooltip);
this.ribbonIconEl.setAttribute("title", tooltip);
}
async loadSettings() {
const rawData = (await this.loadData()) as unknown;
const settings = await loadSettingsWithKeychain(rawData, (d) => this.saveData(d));

View file

@ -187,7 +187,6 @@ describe("sanitizeSettings - agentMode shape migration", () => {
agentMode: undefined as unknown as never,
});
expect(sanitized.agentMode).toEqual({
enabled: true,
byok: {},
mcpServers: [],
activeBackend: "opencode",

View file

@ -230,7 +230,6 @@ export interface CopilotSettings {
settingsVersion?: number;
/** Agent Mode (ACP-backed BYOK agent harness). Desktop only. */
agentMode: {
enabled: boolean;
byok: { anthropic?: string; openai?: string; google?: string };
/**
* User-configured MCP servers passed to the agent on session start.
@ -844,7 +843,6 @@ function sanitizeAgentMode(raw: unknown): CopilotSettings["agentMode"] {
return { ...DEFAULT_SETTINGS.agentMode };
}
const r = raw as Record<string, unknown>;
const enabled = typeof r.enabled === "boolean" ? r.enabled : DEFAULT_SETTINGS.agentMode.enabled;
const byok =
r.byok && typeof r.byok === "object"
? (r.byok as { anthropic?: string; openai?: string; google?: string })
@ -904,7 +902,6 @@ function sanitizeAgentMode(raw: unknown): CopilotSettings["agentMode"] {
};
return {
enabled,
byok,
mcpServers,
activeBackend,

View file

@ -50,34 +50,21 @@ export const AgentSettings: React.FC = () => {
<div className="tw-mb-3 tw-text-xl tw-font-bold">Agents (alpha)</div>
<div className="tw-space-y-4">
<SettingItem
type="switch"
title="Enable Agent Mode"
description="BYOK agent harness backed by a local ACP subprocess. Desktop only."
checked={settings.agentMode.enabled}
onCheckedChange={(checked) =>
setSettings((cur) => ({ agentMode: { ...cur.agentMode, enabled: checked } }))
type="select"
title="Default backend"
description="Used when you click + to start a new session and for auto-spawn on mount. Selecting a model from the model picker also updates this."
value={settings.agentMode.activeBackend}
onChange={(value) =>
setSettings((cur) => ({ agentMode: { ...cur.agentMode, activeBackend: value } }))
}
options={orderedDescriptors.map((d) => ({ label: d.displayName, value: d.id }))}
/>
{settings.agentMode.enabled && (
<SettingItem
type="select"
title="Default backend"
description="Used when you click + to start a new session and for auto-spawn on mount. Selecting a model from the model picker also updates this."
value={settings.agentMode.activeBackend}
onChange={(value) =>
setSettings((cur) => ({ agentMode: { ...cur.agentMode, activeBackend: value } }))
}
options={orderedDescriptors.map((d) => ({ label: d.displayName, value: d.id }))}
/>
)}
<McpServersPanel />
{settings.agentMode.enabled && <McpServersPanel />}
{settings.agentMode.enabled &&
orderedDescriptors.map((descriptor) => (
<BackendSection key={descriptor.id} descriptor={descriptor} plugin={plugin} />
))}
{orderedDescriptors.map((descriptor) => (
<BackendSection key={descriptor.id} descriptor={descriptor} plugin={plugin} />
))}
</div>
</section>
);