/ migrations / migrateSonnet45ToSonnet46.ts
migrateSonnet45ToSonnet46.ts
 1  import {
 2    type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
 3    logEvent,
 4  } from '../services/analytics/index.js'
 5  import {
 6    isMaxSubscriber,
 7    isProSubscriber,
 8    isTeamPremiumSubscriber,
 9  } from '../utils/auth.js'
10  import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
11  import { getAPIProvider } from '../utils/model/providers.js'
12  import {
13    getSettingsForSource,
14    updateSettingsForSource,
15  } from '../utils/settings/settings.js'
16  
17  /**
18   * Migrate Pro/Max/Team Premium first-party users off explicit Sonnet 4.5
19   * model strings to the 'sonnet' alias (which now resolves to Sonnet 4.6).
20   *
21   * Users may have been pinned to explicit Sonnet 4.5 strings by:
22   * - The earlier migrateSonnet1mToSonnet45 migration (sonnet[1m] → explicit 4.5[1m])
23   * - Manually selecting it via /model
24   *
25   * Reads userSettings specifically (not merged) so we only migrate what /model
26   * wrote — project/local pins are left alone.
27   * Idempotent: only writes if userSettings.model matches a Sonnet 4.5 string.
28   */
29  export function migrateSonnet45ToSonnet46(): void {
30    if (getAPIProvider() !== 'firstParty') {
31      return
32    }
33  
34    if (!isProSubscriber() && !isMaxSubscriber() && !isTeamPremiumSubscriber()) {
35      return
36    }
37  
38    const model = getSettingsForSource('userSettings')?.model
39    if (
40      model !== 'claude-sonnet-4-5-20250929' &&
41      model !== 'claude-sonnet-4-5-20250929[1m]' &&
42      model !== 'sonnet-4-5-20250929' &&
43      model !== 'sonnet-4-5-20250929[1m]'
44    ) {
45      return
46    }
47  
48    const has1m = model.endsWith('[1m]')
49    updateSettingsForSource('userSettings', {
50      model: has1m ? 'sonnet[1m]' : 'sonnet',
51    })
52  
53    // Skip notification for brand-new users — they never experienced the old default
54    const config = getGlobalConfig()
55    if (config.numStartups > 1) {
56      saveGlobalConfig(current => ({
57        ...current,
58        sonnet45To46MigrationTimestamp: Date.now(),
59      }))
60    }
61  
62    logEvent('tengu_sonnet45_to_46_migration', {
63      from_model:
64        model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
65      has_1m: has1m,
66    })
67  }