From 0c378889d1b346039a709b0c17d8b7a15cd29d92 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 1 Nov 2026 17:20:51 +0100 Subject: [PATCH] fix(server): an option a session drops when opening is not brought back by a configured default The opening snapshot merged defaults over the options after the session's openOptionsPatch had removed a key. Defaults now merge into what the session was given and the patch applies after. --- .../src/server/agent/agent-manager.test.ts | 9 +++++++++ .../server/src/server/agent/agent-manager.ts | 19 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/server/src/server/agent/agent-manager.test.ts b/packages/server/src/server/agent/agent-manager.test.ts index 1df2f35502..19cf30eb07 100644 --- a/packages/server/src/server/agent/agent-manager.test.ts +++ b/packages/server/src/server/agent/agent-manager.test.ts @@ -12895,6 +12895,15 @@ describe("agent options", () => { expect(published.every((options) => options?.service_tier === "slow")).toBe(true); }); + test("an option the session dropped when opening does not come back from a configured default", async () => { + const { manager, agentId } = await createOptionsAgent(undefined, { service_tier: null }); + + const agent = manager.getAgent(agentId); + expect(agent?.effectiveOptions).toEqual({}); + await manager.markAgentUnread(agentId); + expect(toAgentPayload(manager.getAgent(agentId)!).options).toEqual({}); + }); + test("an option without a control is settable through the patch and readable in the snapshot", async () => { const { manager, client, storage, agentId } = await createOptionsAgent(); diff --git a/packages/server/src/server/agent/agent-manager.ts b/packages/server/src/server/agent/agent-manager.ts index 5881737006..2c472e2ee5 100644 --- a/packages/server/src/server/agent/agent-manager.ts +++ b/packages/server/src/server/agent/agent-manager.ts @@ -3910,6 +3910,12 @@ export class AgentManager { resolvedAgentId, session, config, + // Defaults merge into what the session was given; what it reports it ended up with comes + // after, so an option it dropped does not come back from a default. + effectiveOptions: applyProviderOptionsPatch({ + options: this.effectiveOptionsFor(openedConfig.provider, openedConfig.providerOptions), + patch: session.openOptionsPatch ?? {}, + }), now, durableTimelineHasRows, options, @@ -4054,6 +4060,7 @@ export class AgentManager { resolvedAgentId: string; session: AgentSession; config: AgentSessionConfig; + effectiveOptions: ProviderOptions; now: Date; durableTimelineHasRows: boolean; options: @@ -4073,7 +4080,15 @@ export class AgentManager { } | undefined; }): ActiveManagedAgent { - const { resolvedAgentId, session, config, now, durableTimelineHasRows, options } = params; + const { + resolvedAgentId, + session, + config, + effectiveOptions, + now, + durableTimelineHasRows, + options, + } = params; return { id: resolvedAgentId, provider: config.provider, @@ -4085,7 +4100,7 @@ export class AgentManager { capabilities: session.capabilities, config, // What the session opened with. Provider defaults edited later reach it when it next opens. - effectiveOptions: this.effectiveOptionsFor(config.provider, config.providerOptions), + effectiveOptions, runtimeInfo: undefined, lifecycle: "initializing", createdAt: options?.createdAt ?? now,