From 822388e2f383531728f74dfe1db817173b99e477 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 1 Nov 2026 10:21:55 +0100 Subject: [PATCH] fix(server): let a held OMP Fast option follow the runtime when it changes by itself OMP tracks Fast per model family, so switching models can turn it off. The session now reports that as an option change when a fast_mode option is held, instead of leaving the stored option true while the runtime reports false. --- .../server/agent/providers/omp/agent.test.ts | 29 +++++++++++++++++++ .../src/server/agent/providers/omp/agent.ts | 17 +++++++++++ 2 files changed, 46 insertions(+) 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 {