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 794dc41278..f31cb4d995 100644 --- a/packages/server/src/server/agent/providers/omp/agent.test.ts +++ b/packages/server/src/server/agent/providers/omp/agent.test.ts @@ -677,6 +677,35 @@ describe("OMP agent client and session", () => { expect(session.controls).toHaveLength(1); }); + test("a Fast change OMP makes by itself replaces the held fast_mode option", async () => { + const omp = new OmpHarness(); + await omp.start({ model: "openai/gpt-5" }); + const session = omp.requireSession(); + const events: AgentStreamEvent[] = []; + session.subscribe((event) => events.push(event)); + omp.runtime().fastModeResult = { enabled: true, active: true }; + await session.applyOptions?.({ fast_mode: true }); + + // Another model family has its own Fast tier, which is unset. + omp.runtime().setModelResult = { provider: "anthropic", id: "claude-x" }; + omp.runtime().queueStateReports([ + { + ...omp.runtime().state, + model: omp.runtime().setModelResult, + fastModeEnabled: false, + fastModeActive: false, + }, + ]); + await session.setModel?.("anthropic/claude-x"); + + expect(events.filter((event) => event.type === "options_changed")).toEqual([ + { type: "options_changed", provider: "omp", patch: { fast_mode: false } }, + ]); + // The options the manager now holds leave the runtime alone. + await session.applyOptions?.({ fast_mode: false }); + expect(omp.runtime().setFastModeRequests).toEqual([true]); + }); + test("switching model refreshes whether Fast applies", async () => { const omp = new OmpHarness(); await omp.start({ model: "openrouter/google/gemini-3.8-flash" }); diff --git a/packages/server/src/server/agent/providers/omp/agent.ts b/packages/server/src/server/agent/providers/omp/agent.ts index 1bcf34d7f3..974d56f8d4 100644 --- a/packages/server/src/server/agent/providers/omp/agent.ts +++ b/packages/server/src/server/agent/providers/omp/agent.ts @@ -2247,6 +2247,23 @@ export class OmpAgentSession implements AgentSession { private async refreshState(): Promise { this.state = await this.runtimeSession.getState(); + this.followRuntimeFastMode(); + } + + /** + * OMP tracks Fast per model family, so switching models can change it. A held `fast_mode` + * option follows what the runtime reports; with no option held, the control's default shows it. + */ + private followRuntimeFastMode(): void { + const held = this.config.providerOptions?.fast_mode; + const reported = this.state.fastModeEnabled; + if (typeof held !== "boolean" || typeof reported !== "boolean" || held === reported) return; + this.config.providerOptions = { ...this.config.providerOptions, fast_mode: reported }; + this.emit({ + type: "options_changed", + provider: this.provider, + patch: { fast_mode: reported }, + }); } private async refreshAfterTurn(finalUsage: Promise): Promise {