From dd195034484fd0a72165c6851e7c6516eec2039d Mon Sep 17 00:00:00 2001 From: Lifei Zhou Date: Sat, 27 Jun 2026 16:42:25 +1000 Subject: [PATCH 1/3] update the sesion store after session provider and model update --- .../src/acp/__tests__/providers.test.ts | 69 +++++++++++++++++ ui/desktop/src/acp/providers.ts | 74 ++++++++++++++++++- .../components/ModelAndProviderContext.tsx | 32 +++++++- 3 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 ui/desktop/src/acp/__tests__/providers.test.ts diff --git a/ui/desktop/src/acp/__tests__/providers.test.ts b/ui/desktop/src/acp/__tests__/providers.test.ts new file mode 100644 index 000000000000..5f13b4f3680e --- /dev/null +++ b/ui/desktop/src/acp/__tests__/providers.test.ts @@ -0,0 +1,69 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { getAcpClient } from '../acpConnection'; +import { acpSetSessionProviderModel } from '../providers'; + +vi.mock('../acpConnection', () => ({ + getAcpClient: vi.fn(), +})); + +function selectConfigOption(id: string, currentValue: string) { + return { + id, + name: id, + kind: { + type: 'select', + currentValue, + options: [], + }, + }; +} + +describe('ACP providers', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('returns provider and model from the final model config response', async () => { + const client = { + setSessionConfigOption: vi + .fn() + .mockResolvedValueOnce({ + configOptions: [ + selectConfigOption('provider', 'anthropic'), + selectConfigOption('model', 'provider-default-model'), + ], + }) + .mockResolvedValueOnce({ + configOptions: [ + selectConfigOption('provider', 'anthropic'), + selectConfigOption('model', 'claude-sonnet-4-5'), + ], + }), + }; + vi.mocked(getAcpClient).mockResolvedValue( + client as unknown as Awaited> + ); + + const applied = await acpSetSessionProviderModel( + 'session-1', + 'anthropic', + 'claude-sonnet-4-5' + ); + + expect(client.setSessionConfigOption).toHaveBeenCalledTimes(2); + expect(client.setSessionConfigOption).toHaveBeenNthCalledWith(1, { + sessionId: 'session-1', + configId: 'provider', + value: 'anthropic', + }); + expect(client.setSessionConfigOption).toHaveBeenNthCalledWith(2, { + sessionId: 'session-1', + configId: 'model', + value: 'claude-sonnet-4-5', + }); + expect(applied).toEqual({ + providerId: 'anthropic', + modelId: 'claude-sonnet-4-5', + }); + }); +}); diff --git a/ui/desktop/src/acp/providers.ts b/ui/desktop/src/acp/providers.ts index 933559a17ad2..2da989587f37 100644 --- a/ui/desktop/src/acp/providers.ts +++ b/ui/desktop/src/acp/providers.ts @@ -198,6 +198,64 @@ export async function acpSaveThinkingEffort(effort: ThinkingEffort): Promise { +): Promise { const client = await getAcpClient(); - await client.setSessionConfigOption({ sessionId, configId: 'provider', value: providerId }); + let response = await client.setSessionConfigOption({ + sessionId, + configId: 'provider', + value: providerId, + }); if (modelId) { - await client.setSessionConfigOption({ sessionId, configId: 'model', value: modelId }); + response = await client.setSessionConfigOption({ + sessionId, + configId: 'model', + value: modelId, + }); } + + return extractAppliedSessionProviderModel(response.configOptions); } diff --git a/ui/desktop/src/components/ModelAndProviderContext.tsx b/ui/desktop/src/components/ModelAndProviderContext.tsx index 077c3b349567..056685b44fc3 100644 --- a/ui/desktop/src/components/ModelAndProviderContext.tsx +++ b/ui/desktop/src/components/ModelAndProviderContext.tsx @@ -2,7 +2,13 @@ import React, { createContext, useContext, useState, useEffect, useMemo, useCall import { toastError, toastSuccess } from '../toasts'; import Model, { getProviderMetadata } from './settings/models/modelInterface'; import { ProviderMetadata } from '../api'; -import { acpReadDefaults, acpSaveDefaults, acpSetSessionProviderModel } from '../acp/providers'; +import { acpChatSessionActions, acpChatSessionStore } from '../acp/chatSessionStore'; +import { + acpReadDefaults, + acpSaveDefaults, + acpSetSessionProviderModel, + type AppliedSessionProviderModel, +} from '../acp/providers'; import { errorMessage } from '../utils/conversionUtils'; import { getModelDisplayName, @@ -57,6 +63,27 @@ const ModelAndProviderContext = createContext = ({ children }) => { const [currentModel, setCurrentModel] = useState(null); const [currentProvider, setCurrentProvider] = useState(null); @@ -70,7 +97,8 @@ export const ModelAndProviderProvider: React.FC = try { if (sessionId) { - await acpSetSessionProviderModel(sessionId, providerName, modelName); + const applied = await acpSetSessionProviderModel(sessionId, providerName, modelName); + patchAcpSessionProviderModel(sessionId, applied); } // Only update the global config default when there's no session From 79f989cd93a3fd6063845a4a141d3acff4beced9 Mon Sep 17 00:00:00 2001 From: Lifei Zhou Date: Sat, 27 Jun 2026 17:08:46 +1000 Subject: [PATCH 2/3] update thinking effort when switching model --- .../src/acp/__tests__/providers.test.ts | 19 ++++++++++++++++--- ui/desktop/src/acp/providers.ts | 10 +++++++++- .../components/ModelAndProviderContext.tsx | 7 ++++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ui/desktop/src/acp/__tests__/providers.test.ts b/ui/desktop/src/acp/__tests__/providers.test.ts index 5f13b4f3680e..9a5b59d1b076 100644 --- a/ui/desktop/src/acp/__tests__/providers.test.ts +++ b/ui/desktop/src/acp/__tests__/providers.test.ts @@ -23,7 +23,7 @@ describe('ACP providers', () => { vi.clearAllMocks(); }); - it('returns provider and model from the final model config response', async () => { + it('sets thinking effort after provider and model, then returns the final config response', async () => { const client = { setSessionConfigOption: vi .fn() @@ -38,6 +38,13 @@ describe('ACP providers', () => { selectConfigOption('provider', 'anthropic'), selectConfigOption('model', 'claude-sonnet-4-5'), ], + }) + .mockResolvedValueOnce({ + configOptions: [ + selectConfigOption('provider', 'anthropic'), + selectConfigOption('model', 'claude-sonnet-4-5'), + selectConfigOption('thinking_effort', 'high'), + ], }), }; vi.mocked(getAcpClient).mockResolvedValue( @@ -47,10 +54,11 @@ describe('ACP providers', () => { const applied = await acpSetSessionProviderModel( 'session-1', 'anthropic', - 'claude-sonnet-4-5' + 'claude-sonnet-4-5', + 'high' ); - expect(client.setSessionConfigOption).toHaveBeenCalledTimes(2); + expect(client.setSessionConfigOption).toHaveBeenCalledTimes(3); expect(client.setSessionConfigOption).toHaveBeenNthCalledWith(1, { sessionId: 'session-1', configId: 'provider', @@ -61,6 +69,11 @@ describe('ACP providers', () => { configId: 'model', value: 'claude-sonnet-4-5', }); + expect(client.setSessionConfigOption).toHaveBeenNthCalledWith(3, { + sessionId: 'session-1', + configId: 'thinking_effort', + value: 'high', + }); expect(applied).toEqual({ providerId: 'anthropic', modelId: 'claude-sonnet-4-5', diff --git a/ui/desktop/src/acp/providers.ts b/ui/desktop/src/acp/providers.ts index 2da989587f37..f3cce163aad9 100644 --- a/ui/desktop/src/acp/providers.ts +++ b/ui/desktop/src/acp/providers.ts @@ -265,7 +265,8 @@ function selectCurrentValue(kind: unknown): unknown { export async function acpSetSessionProviderModel( sessionId: string, providerId: string, - modelId?: string | null + modelId?: string | null, + thinkingEffort?: ThinkingEffort | null ): Promise { const client = await getAcpClient(); let response = await client.setSessionConfigOption({ @@ -280,6 +281,13 @@ export async function acpSetSessionProviderModel( value: modelId, }); } + if (thinkingEffort != null) { + response = await client.setSessionConfigOption({ + sessionId, + configId: 'thinking_effort', + value: thinkingEffort, + }); + } return extractAppliedSessionProviderModel(response.configOptions); } diff --git a/ui/desktop/src/components/ModelAndProviderContext.tsx b/ui/desktop/src/components/ModelAndProviderContext.tsx index 056685b44fc3..81b41baa48b7 100644 --- a/ui/desktop/src/components/ModelAndProviderContext.tsx +++ b/ui/desktop/src/components/ModelAndProviderContext.tsx @@ -97,7 +97,12 @@ export const ModelAndProviderProvider: React.FC = try { if (sessionId) { - const applied = await acpSetSessionProviderModel(sessionId, providerName, modelName); + const applied = await acpSetSessionProviderModel( + sessionId, + providerName, + modelName, + model.request_params?.thinking_effort ?? null + ); patchAcpSessionProviderModel(sessionId, applied); } From f7ecbc52b68b49fcb389de003bcdf26af4d011f8 Mon Sep 17 00:00:00 2001 From: Lifei Zhou Date: Sat, 27 Jun 2026 17:17:32 +1000 Subject: [PATCH 3/3] clean up --- ui/desktop/src/acp/__tests__/providers.test.ts | 8 +++----- ui/desktop/src/acp/providers.ts | 13 ++----------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/ui/desktop/src/acp/__tests__/providers.test.ts b/ui/desktop/src/acp/__tests__/providers.test.ts index 9a5b59d1b076..0d419e244e1d 100644 --- a/ui/desktop/src/acp/__tests__/providers.test.ts +++ b/ui/desktop/src/acp/__tests__/providers.test.ts @@ -10,11 +10,9 @@ function selectConfigOption(id: string, currentValue: string) { return { id, name: id, - kind: { - type: 'select', - currentValue, - options: [], - }, + type: 'select', + currentValue, + options: [], }; } diff --git a/ui/desktop/src/acp/providers.ts b/ui/desktop/src/acp/providers.ts index f3cce163aad9..e2e2100ce961 100644 --- a/ui/desktop/src/acp/providers.ts +++ b/ui/desktop/src/acp/providers.ts @@ -220,7 +220,7 @@ function extractAppliedSessionProviderModel(configOptions: unknown): AppliedSess continue; } - const currentValue = selectCurrentValue('kind' in option ? option.kind : undefined); + const currentValue = selectCurrentValue(option); if (typeof currentValue !== 'string') { continue; } @@ -244,16 +244,7 @@ function selectCurrentValue(kind: unknown): unknown { return kind.currentValue; } - if (!('select' in kind)) { - return undefined; - } - - const select = kind.select; - if (!select || typeof select !== 'object' || !('currentValue' in select)) { - return undefined; - } - - return select.currentValue; + return undefined; } /**