From afa37dd61ea5f9dbf5e217e0252737cf58dbe61f Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:52:26 -0700 Subject: [PATCH] fix(source-control): reach users Orca already pinned to Pi's Copilot default Orca seeded selectedModelByAgent.pi = github-copilot/gpt-5.4-mini the first time a user picked Pi on a pre-fix build, and pi --list-models still lists that id, so the resolution chain honoured it and STA-4249 kept reproducing for every upgrading user. Every prior test started from an empty selection. --- src/shared/commit-message-agent-spec.ts | 8 +++++++ src/shared/source-control-ai.test.ts | 32 +++++++++++++++++++++++++ src/shared/source-control-ai.ts | 14 ++++++++--- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/shared/commit-message-agent-spec.ts b/src/shared/commit-message-agent-spec.ts index 8525bf72f8c..a02682cc11f 100644 --- a/src/shared/commit-message-agent-spec.ts +++ b/src/shared/commit-message-agent-spec.ts @@ -109,6 +109,14 @@ const CLAUDE_THINKING_LEVELS: ThinkingLevel[] = [ const PI_DEFAULT_MODEL_ID = 'default' +/** + * The model id Orca used to persist for Pi before `Pi default` existed. Orca itself + * seeded this into `selectedModelByAgent.pi` the first time a user picked Pi, so a + * pre-upgrade user carries it even though they never chose a Copilot model. Treated + * as "no selection" on read so the fix reaches them (STA-4249). + */ +export const PI_RETIRED_COPILOT_DEFAULT_MODEL_ID = 'github-copilot/gpt-5.4-mini' + function uniqueModels(models: CommitMessageModel[]): CommitMessageModel[] { const seen = new Set() return models.filter((model) => { diff --git a/src/shared/source-control-ai.test.ts b/src/shared/source-control-ai.test.ts index 3896de10a46..d506d4a510e 100644 --- a/src/shared/source-control-ai.test.ts +++ b/src/shared/source-control-ai.test.ts @@ -118,6 +118,38 @@ describe('source-control AI resolution', () => { } ) + // Why: Orca seeded `github-copilot/gpt-5.4-mini` into selectedModelByAgent.pi the + // first time a user picked Pi on a pre-fix build, and `pi --list-models` still + // lists it, so the resolution chain honoured it and STA-4249 kept reproducing for + // every upgrading user. The other cases here all start from an empty selection. + it.each(['commitMessage', 'pullRequest', 'branchName'] as const)( + 'ignores the retired Copilot default that Orca persisted for Pi, for %s', + (operation) => { + const base = piSettings() + base.sourceControlAi!.selectedModelByAgent = { pi: 'github-copilot/gpt-5.4-mini' } + base.commitMessageAi!.selectedModelByAgent = { pi: 'github-copilot/gpt-5.4-mini' } + base.sourceControlAi!.discoveredModelsByAgent = { + pi: [{ id: 'github-copilot/gpt-5.4-mini', label: 'GPT-5.4 mini' }] + } + + const resolved = resolveSourceControlAiForOperation({ + settings: base, + repo: null, + operation, + discoveryHostKey: 'local' + }) + expect(resolved.ok).toBe(true) + if (!resolved.ok) { + throw new Error(resolved.error) + } + const result = planCommitMessageGeneration(resolved.value.params, 'PROMPT') + + expect(result).toMatchObject({ ok: true }) + expect(result.ok && result.plan.args).not.toContain('--model') + expect(result.ok && result.plan.args).not.toContain('github-copilot/gpt-5.4-mini') + } + ) + it.each(['commitMessage', 'pullRequest', 'branchName'] as const)( 'passes an explicit Pi model override for %s', (operation) => { diff --git a/src/shared/source-control-ai.ts b/src/shared/source-control-ai.ts index 72669000186..b7072ac67f8 100644 --- a/src/shared/source-control-ai.ts +++ b/src/shared/source-control-ai.ts @@ -8,7 +8,8 @@ import { listCommitMessageAgentCapabilities, type CustomAgentId, isCustomAgentId, - resolveCommitMessageAgentChoice + resolveCommitMessageAgentChoice, + PI_RETIRED_COPILOT_DEFAULT_MODEL_ID } from './commit-message-agent-spec' import { LOCAL_COMMIT_MESSAGE_HOST_KEY } from './commit-message-host-key' import { @@ -949,7 +950,7 @@ function selectPersistedModelId(args: { defaultModelId: string }): string { const { source, legacy, repoOverrides, operation, hostKey, agentId, defaultModelId } = args - return ( + const persisted = readSourceControlAiModelChoiceForHost( repoOverrides?.modelOverridesByOperation?.[operation], hostKey, @@ -966,7 +967,14 @@ function selectPersistedModelId(args: { ? legacy?.selectedModelByAgent?.[agentId] : undefined) ?? defaultModelId - ) + // Why: Orca seeded `github-copilot/gpt-5.4-mini` into Pi's persisted selection + // before `Pi default` existed, so a pre-upgrade user is pinned to a Copilot model + // they never chose and STA-4249 would still reproduce for them. Discovery still + // lists that id, so the resolution chain below would otherwise honour it. + if (agentId === 'pi' && persisted === PI_RETIRED_COPILOT_DEFAULT_MODEL_ID) { + return defaultModelId + } + return persisted } function resolveThinkingLevel(args: {