diff --git a/packages/coding-agent/src/modes/rpc/rpc-client.ts b/packages/coding-agent/src/modes/rpc/rpc-client.ts index ef9b06541..a83c09711 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-client.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-client.ts @@ -600,6 +600,14 @@ export class RpcClient { return this.#getData(response); } + /** + * Enable or disable fast mode for the active model family. + */ + async setFastMode(enabled: boolean): Promise<{ enabled: boolean; active: boolean }> { + const response = await this.#send({ type: "set_fast_mode", enabled }); + return this.#getData(response); + } + /** * Configure subagent frames emitted by the RPC server. Servers default to "off". * "progress" emits lifecycle/progress frames; "events" additionally emits raw subagent session events. diff --git a/packages/coding-agent/src/modes/rpc/rpc-mode.ts b/packages/coding-agent/src/modes/rpc/rpc-mode.ts index 19b74c64c..99267f77b 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-mode.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-mode.ts @@ -1084,9 +1084,11 @@ export async function runRpcMode( sessionId: session.sessionId, sessionName: session.sessionName, autoCompactionEnabled: session.autoCompactionEnabled, - messageCount: session.messages.length, queuedMessageCount: session.queuedMessageCount, todoPhases: session.getTodoPhases(), + fastModeEnabled: session.isFastModeEnabled(), + fastModeActive: session.isFastModeActive(), + messageCount: session.messages.length, systemPrompt: session.systemPrompt, dumpTools: session.agent.state.tools.map(tool => ({ name: tool.name, @@ -1099,6 +1101,16 @@ export async function runRpcMode( return success(id, "get_state", state); } + case "set_fast_mode": { + if (!session.setFastMode(command.enabled)) { + return error(id, "set_fast_mode", "Fast mode is unavailable for the current model."); + } + return success(id, "set_fast_mode", { + enabled: session.isFastModeEnabled(), + active: session.isFastModeActive(), + }); + } + case "get_available_commands": { return success(id, "get_available_commands", { commands: await getAvailableCommands() }); } diff --git a/packages/coding-agent/src/modes/rpc/rpc-types.ts b/packages/coding-agent/src/modes/rpc/rpc-types.ts index ab409a959..6ccd69381 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-types.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-types.ts @@ -39,6 +39,7 @@ export type RpcCommand = // State | { id?: string; type: "get_state" } + | { id?: string; type: "set_fast_mode"; enabled: boolean } | { id?: string; type: "get_available_commands" } | { id?: string; type: "set_todos"; phases: TodoPhase[] } | { id?: string; type: "set_host_tools"; tools: RpcHostToolDefinition[] } @@ -107,6 +108,8 @@ export interface RpcSessionState { sessionId: string; sessionName?: string; autoCompactionEnabled: boolean; + fastModeEnabled: boolean; + fastModeActive: boolean; messageCount: number; queuedMessageCount: number; todoPhases: TodoPhase[]; @@ -209,6 +212,13 @@ export type RpcResponse = // State | { id?: string; type: "response"; command: "get_state"; success: true; data: RpcSessionState } + | { + id?: string; + type: "response"; + command: "set_fast_mode"; + success: true; + data: { enabled: boolean; active: boolean }; + } | { id?: string; type: "response"; diff --git a/packages/coding-agent/test/rpc-input-frame.test.ts b/packages/coding-agent/test/rpc-input-frame.test.ts index 0464c32af..88249549a 100644 --- a/packages/coding-agent/test/rpc-input-frame.test.ts +++ b/packages/coding-agent/test/rpc-input-frame.test.ts @@ -324,6 +324,8 @@ describe("RpcInputDispatcher", () => { interruptMode: "immediate", sessionId: "session-1", autoCompactionEnabled: false, + fastModeEnabled: false, + fastModeActive: false, messageCount: 0, queuedMessageCount: 0, todoPhases: [], diff --git a/packages/coding-agent/test/rpc.test.ts b/packages/coding-agent/test/rpc.test.ts index d20da322a..1922659fc 100644 --- a/packages/coding-agent/test/rpc.test.ts +++ b/packages/coding-agent/test/rpc.test.ts @@ -61,6 +61,24 @@ describe.skipIf(!e2eApiKey("ANTHROPIC_API_KEY"))("RPC mode", () => { expect(state.messageCount).toBe(0); }, 30000); + test("should set fast mode and expose enabled/active state", async () => { + await client.start(); + + const enabled = await client.setFastMode(true); + expect(enabled).toEqual({ enabled: true, active: true }); + + const stateWhileEnabled = await client.getState(); + expect(stateWhileEnabled.fastModeEnabled).toBe(true); + expect(stateWhileEnabled.fastModeActive).toBe(true); + + const disabled = await client.setFastMode(false); + expect(disabled).toEqual({ enabled: false, active: false }); + + const stateWhileDisabled = await client.getState(); + expect(stateWhileDisabled.fastModeEnabled).toBe(false); + expect(stateWhileDisabled.fastModeActive).toBe(false); + }, 30000); + test("should save messages to session file", async () => { await client.start();