From 8c3c5a4fd2f558ea79bc82ee26163b46a595d790 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 7d555e310e..17f19cec88 100644 --- a/packages/server/src/server/agent/agent-manager.test.ts +++ b/packages/server/src/server/agent/agent-manager.test.ts @@ -13120,6 +13120,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 6c2dfa2c78..43f093cfee 100644 --- a/packages/server/src/server/agent/agent-manager.ts +++ b/packages/server/src/server/agent/agent-manager.ts @@ -3983,6 +3983,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, background: options?.background === true, @@ -4128,6 +4134,7 @@ export class AgentManager { resolvedAgentId: string; session: AgentSession; config: AgentSessionConfig; + effectiveOptions: ProviderOptions; now: Date; durableTimelineHasRows: boolean; background: boolean; @@ -4148,7 +4155,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, @@ -4160,7 +4175,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,