diff --git a/packages/server/src/server/agent/providers/omp/agent.test.ts b/packages/server/src/server/agent/providers/omp/agent.test.ts index 38a54294b2..a70c017b4c 100644 --- a/packages/server/src/server/agent/providers/omp/agent.test.ts +++ b/packages/server/src/server/agent/providers/omp/agent.test.ts @@ -780,6 +780,18 @@ describe("OMP agent client and session", () => { expect(omp.runtime().setFastModeRequests).toEqual([]); }); + test("a replacement runtime that refuses the Fast the session had publishes what it accepted", async () => { + const omp = new OmpHarness(); + omp.acceptFastOnNextRuntime(); + await omp.start({ modeId: "full", providerOptions: { fast_mode: true } }); + expect(omp.requireSession().openOptionsPatch).toEqual({}); + + // The approval-mode restart starts a second runtime, which refuses Fast. + await omp.setMode("ask"); + + expect(omp.optionsChanges()).toEqual([{ fast_mode: false }]); + }); + test("restores Fast from the initial OMP state on create and resume", async () => { const created = new OmpHarness(); await created.start({ providerOptions: { fast_mode: true } }); diff --git a/packages/server/src/server/agent/providers/omp/agent.ts b/packages/server/src/server/agent/providers/omp/agent.ts index 7fe3e517fa..149e7d475e 100644 --- a/packages/server/src/server/agent/providers/omp/agent.ts +++ b/packages/server/src/server/agent/providers/omp/agent.ts @@ -1095,6 +1095,7 @@ export class OmpAgentSession implements AgentSession { const old = this.runtimeSession; const oldHostTools = this.hostTools; const previousSessionId = this.state.sessionId; + const fastModeBefore = this.state.fastModeEnabled; const restarted = await this.restartRuntime( this.config.internal ? null : (this.state.sessionFile ?? null), modeId, @@ -1115,6 +1116,7 @@ export class OmpAgentSession implements AgentSession { this.config.modeId = modeId; this.runtimeDead = false; this.attachRuntime(next); + this.publishFastModeChange(fastModeBefore); this.subagentIndex.clear(old); await oldHostTools?.close(); await old.close().catch(() => undefined); @@ -2267,6 +2269,11 @@ export class OmpAgentSession implements AgentSession { private async refreshState(): Promise { const before = this.state.fastModeEnabled; this.state = await this.runtimeSession.getState(); + this.publishFastModeChange(before); + } + + // The runtime owns Fast: whatever it accepted is what the session now runs with. + private publishFastModeChange(before: boolean | undefined): void { if (this.state.fastModeEnabled !== before && typeof this.state.fastModeEnabled === "boolean") { this.rememberFastMode(this.state.fastModeEnabled); this.emit({ diff --git a/packages/server/src/server/agent/providers/omp/test-utils/omp-harness.ts b/packages/server/src/server/agent/providers/omp/test-utils/omp-harness.ts index 8be53f1742..8aeaa50312 100644 --- a/packages/server/src/server/agent/providers/omp/test-utils/omp-harness.ts +++ b/packages/server/src/server/agent/providers/omp/test-utils/omp-harness.ts @@ -467,6 +467,16 @@ export class OmpHarness { return this.events.map((event) => event.type); } + acceptFastOnNextRuntime(): void { + this.omp.queueSessionSetup((runtime) => { + runtime.fastModeResult = { enabled: true, active: true }; + }); + } + + optionsChanges(): Record[] { + return this.events.flatMap((event) => (event.type === "options_changed" ? [event.patch] : [])); + } + async history(): Promise { const items: AgentTimelineItem[] = []; for await (const event of this.requireSession().streamHistory()) {