diff --git a/extensions/thronekeeper/src/extension.ts b/extensions/thronekeeper/src/extension.ts index 9e5bbd8..58a0d34 100644 --- a/extensions/thronekeeper/src/extension.ts +++ b/extensions/thronekeeper/src/extension.ts @@ -123,6 +123,9 @@ async function fetchAnthropicDefaults(secrets?: SecretsService): Promise<{ opus: const data: any = await response.body.json(); const models = data.data || []; + // DEBUG: Log all raw model IDs before filtering + console.log(`[fetchAnthropicDefaults] All ${models.length} models from API:`, models.map((m: any) => m.id)); + // Helper to select best model: prefer -latest alias, exclude -preview and other unstable suffixes const selectBestModel = (filtered: any[], fallback: string): string => { if (filtered.length === 0) return fallback; @@ -187,15 +190,15 @@ async function fetchAnthropicDefaults(secrets?: SecretsService): Promise<{ opus: // Find latest Opus model const opusModels = models.filter((m: any) => m.id.includes('opus')); - const opus = selectBestModel(opusModels, 'claude-opus-4-1-20250805'); + const opus = selectBestModel(opusModels, 'claude-opus-4-6-latest'); // Find latest Sonnet model const sonnetModels = models.filter((m: any) => m.id.includes('sonnet')); - const sonnet = selectBestModel(sonnetModels, 'claude-sonnet-4-5-20250929'); + const sonnet = selectBestModel(sonnetModels, 'claude-sonnet-4-6-latest'); // Find latest Haiku model const haikuModels = models.filter((m: any) => m.id.includes('haiku')); - const haiku = selectBestModel(haikuModels, 'claude-3-5-haiku-latest'); + const haiku = selectBestModel(haikuModels, 'claude-haiku-4-5-latest'); // Add detailed logging console.log(`[fetchAnthropicDefaults] Model selection summary:`); @@ -217,7 +220,7 @@ async function fetchAnthropicDefaults(secrets?: SecretsService): Promise<{ opus: const authStatus = secrets ? (await secrets.getAnthropicKey() ? 'authenticated' : 'unauthenticated') : 'no secrets service'; console.error(`[fetchAnthropicDefaults] Failed to fetch (${authStatus}):`, error); // Return hardcoded fallbacks if fetch fails - return { opus: 'claude-opus-4-1-20250805', sonnet: 'claude-sonnet-4-5-20250929', haiku: 'claude-3-5-haiku-latest' }; + return { opus: 'claude-opus-4-6-latest', sonnet: 'claude-sonnet-4-6-latest', haiku: 'claude-haiku-4-5-latest' }; } } @@ -351,89 +354,26 @@ export function activate(context: vscode.ExtensionContext) { } } - // Check cache age before fetching fresh defaults - const cachedTimestamp = cfg.get('anthropicDefaultsTimestamp', 0); - const cacheAge = Date.now() - cachedTimestamp; - const stalenessThreshold = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds - - if (cachedTimestamp > 0 && cacheAge > stalenessThreshold) { - const daysOld = Math.floor(cacheAge / (24 * 60 * 60 * 1000)); - log.appendLine(`[revertApply] ⚠️ Cache is ${daysOld} days old (threshold: 7 days), fetching fresh defaults...`); - } else if (cachedTimestamp > 0) { - const daysOld = Math.floor(cacheAge / (24 * 60 * 60 * 1000)); - log.appendLine(`[revertApply] Cache is ${daysOld} days old, fetching fresh defaults...`); - } else { - log.appendLine('[revertApply] No cache timestamp found, fetching fresh defaults...'); - } - - // Try to fetch fresh defaults from API (if key is available) - log.appendLine('[revertApply] Attempting to fetch fresh Anthropic model defaults...'); - let defaults = await fetchAnthropicDefaults(secrets); - let usedFreshDefaults = true; - - if (defaults.opus && defaults.sonnet && defaults.haiku) { - log.appendLine(`[revertApply] ✅ Fetched fresh defaults: opus=${defaults.opus}, sonnet=${defaults.sonnet}, haiku=${defaults.haiku}`); - - // Update cache with fresh values using safe configuration updates - const defaultsSuccess = await safeConfigUpdate( - cfg, - 'anthropicDefaults', - defaults, - vscode.ConfigurationTarget.Global - ); - - const timestampSuccess = await safeConfigUpdate( - cfg, - 'anthropicDefaultsTimestamp', - Date.now(), - vscode.ConfigurationTarget.Global - ); - - if (!defaultsSuccess || !timestampSuccess) { - log.appendLine('[revertApply] ⚠️ Failed to cache fresh defaults, but will continue with revert operation'); - } - } else { - // Should not happen since fetchAnthropicDefaults always returns defaults, but keep fallback logic - log.appendLine('[revertApply] ⚠️ Unexpected: defaults missing fields, falling back to cached values'); - usedFreshDefaults = false; - const cached = cfg.get('anthropicDefaults', null); - if (cached) defaults = cached; - } - - // Single atomic operation: remove Thronekeeper overrides and restore Anthropic defaults + // Remove ALL ThroneKeeper overrides — let Claude Code use its built-in defaults. + // No need to fetch from Anthropic API; Claude Code resolves its own defaults + // when these keys are absent from settings. if (settingsDir) { const restoreEnv: Record = { - // Always set base URL to Anthropic - ANTHROPIC_BASE_URL: 'https://api.anthropic.com', + ANTHROPIC_BASE_URL: null, + ANTHROPIC_MODEL: null, + ANTHROPIC_DEFAULT_OPUS_MODEL: null, + ANTHROPIC_DEFAULT_SONNET_MODEL: null, + ANTHROPIC_DEFAULT_HAIKU_MODEL: null, + API_TIMEOUT_MS: null, + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: null, + CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: null, }; - - // If we have cached defaults, restore model settings - if (defaults?.opus && defaults?.sonnet && defaults?.haiku) { - restoreEnv.ANTHROPIC_MODEL = defaults.sonnet; - restoreEnv.ANTHROPIC_DEFAULT_OPUS_MODEL = defaults.opus; - restoreEnv.ANTHROPIC_DEFAULT_SONNET_MODEL = defaults.sonnet; - restoreEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL = defaults.haiku; - } else { - // No cached defaults: explicitly remove model env vars - // (Claude Code will use its own defaults) - restoreEnv.ANTHROPIC_MODEL = null; - restoreEnv.ANTHROPIC_DEFAULT_OPUS_MODEL = null; - restoreEnv.ANTHROPIC_DEFAULT_SONNET_MODEL = null; - restoreEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL = null; - } - - // Remove Claude Code environment variables when reverting - restoreEnv.API_TIMEOUT_MS = null; - restoreEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = null; - restoreEnv.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = null; - - // Single call: atomic update - await updateClaudeSettings(settingsDir, restoreEnv, /*revert*/ false); + await updateClaudeSettings(settingsDir, restoreEnv, /*revert=*/ false); } - + // NOTE: We do NOT clear reasoningModel/completionModel here anymore // User's saved model preferences should persist across proxy stop/start cycles - // Only .claude/settings.json is reverted to Anthropic defaults for Claude Code CLI + // Only .claude/settings.json is reverted to clean state for Claude Code CLI // Restore base URL to Anthropic defaults in extension settings const candidates: { section: string; key: string }[] = [ @@ -513,14 +453,11 @@ export function activate(context: vscode.ExtensionContext) { const parts: string[] = [] if (restored.length) parts.push(`extensions: ${restored.join(', ')}`) if (termTouched) parts.push(`terminal env: ${termTouched} target(s)`) - if (defaults && defaults.opus && defaults.sonnet && defaults.haiku) { - const source = usedFreshDefaults ? 'fetched latest from API' : 'cached'; - parts.push(`models (${source}): ${defaults.opus.split('-').slice(-1)[0]} (Opus), ${defaults.sonnet.split('-').slice(-1)[0]} (Sonnet), ${defaults.haiku.split('-').slice(-1)[0]} (Haiku)`) - } + if (settingsDir) parts.push('.claude/settings.json cleaned') if (parts.length) { - vscode.window.showInformationMessage(`Restored Anthropic defaults (${parts.join(' | ')}). Open a new terminal for env changes to take effect.`) + vscode.window.showInformationMessage(`Reverted ThroneKeeper overrides (${parts.join(', ')}). Claude Code will use its built-in defaults.`) } else { - vscode.window.showInformationMessage('No Claude overrides were found to restore.') + vscode.window.showInformationMessage('No ThroneKeeper overrides were found to revert.') } } catch (err: any) { log.appendLine(`[revertApply] Unexpected error during revert: ${err?.stack || err}`); @@ -846,7 +783,7 @@ export function activate(context: vscode.ExtensionContext) { const applied: string[] = []; if (applyToExtensions) { - log.appendLine('[applyToClaudeCode] applyToExtensions=true, writing to other extension settings...'); + log.appendLine('[applyToClaudeCode] applyToExtensions=true, writing to other extension settings...') const candidates: { section: string; key: string }[] = [ { section: 'anthropic', key: 'baseUrl' }, { section: 'claude', key: 'baseUrl' }, @@ -1211,6 +1148,8 @@ export function activate(context: vscode.ExtensionContext) { storeTogetherKey, storeDeepseekKey, storeGlmKey, + storeKimiKey, + storeMinimaxKey, storeCustomKey, storeAnyKey, storeAnthropicKey, @@ -1362,4 +1301,4 @@ async function storeKey(provider: Provider, secrets: SecretsService) { export function deactivate() { try { proxy?.stop() } catch {} -} +} \ No newline at end of file