import * as React from 'react' import { useState } from 'react' import type { CommandResultDisplay, LocalJSXCommandContext, } from '../../commands.js' import { Dialog } from '../../components/design-system/Dialog.js' import { FastIcon, getFastIconString } from '../../components/FastIcon.js' import { Box, Link, Text } from '../../ink.js' import { useKeybindings } from '../../keybindings/useKeybinding.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, } from '../../services/analytics/index.js' import { type AppState, useAppState, useSetAppState, } from '../../state/AppState.js' import type { LocalJSXCommandOnDone } from '../../types/command.js' import { clearFastModeCooldown, FAST_MODE_MODEL_DISPLAY, getFastModeModel, getFastModeRuntimeState, getFastModeUnavailableReason, isFastModeEnabled, isFastModeSupportedByModel, prefetchFastModeStatus, } from '../../utils/fastMode.js' import { formatDuration } from '../../utils/format.js' import { formatModelPricing, getOpus46CostTier } from '../../utils/modelCost.js' import { updateSettingsForSource } from '../../utils/settings/settings.js' function applyFastMode( enable: boolean, setAppState: (f: (prev: AppState) => AppState) => void, ): void { clearFastModeCooldown() updateSettingsForSource('userSettings', { fastMode: enable ? true : undefined, }) if (enable) { setAppState(prev => { // Only switch model if current model doesn't support fast mode const needsModelSwitch = !isFastModeSupportedByModel(prev.mainLoopModel) return { ...prev, ...(needsModelSwitch ? { mainLoopModel: getFastModeModel(), mainLoopModelForSession: null } : {}), fastMode: true, } }) } else { setAppState(prev => ({ ...prev, fastMode: false })) } } export function FastModePicker({ onDone, unavailableReason, }: { onDone: ( result?: string, options?: { display?: CommandResultDisplay }, ) => void unavailableReason: string | null }): React.ReactNode { const model = useAppState(s => s.mainLoopModel) const initialFastMode = useAppState(s => s.fastMode) const setAppState = useSetAppState() const [enableFastMode, setEnableFastMode] = useState(initialFastMode ?? false) const runtimeState = getFastModeRuntimeState() const isCooldown = runtimeState.status === 'cooldown' const isUnavailable = unavailableReason !== null const pricing = formatModelPricing(getOpus46CostTier(true)) function handleConfirm(): void { if (isUnavailable) return applyFastMode(enableFastMode, setAppState) logEvent('tengu_fast_mode_toggled', { enabled: enableFastMode, source: 'picker' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }) if (enableFastMode) { const fastIcon = getFastIconString(enableFastMode) const modelUpdated = !isFastModeSupportedByModel(model) ? ` · model set to ${FAST_MODE_MODEL_DISPLAY}` : '' onDone(`${fastIcon} Fast mode ON${modelUpdated} · ${pricing}`) } else { setAppState(prev => ({ ...prev, fastMode: false })) onDone(`Fast mode OFF`) } } function handleCancel(): void { if (isUnavailable) { // Ensure fast mode is off if the org has disabled it if (initialFastMode) { applyFastMode(false, setAppState) } onDone('Fast mode OFF', { display: 'system' }) return } const message = initialFastMode ? `${getFastIconString()} Kept Fast mode ON` : `Kept Fast mode OFF` onDone(message, { display: 'system' }) } function handleToggle(): void { if (isUnavailable) return setEnableFastMode(prev => !prev) } useKeybindings( { 'confirm:yes': handleConfirm, 'confirm:nextField': handleToggle, 'confirm:next': handleToggle, 'confirm:previous': handleToggle, 'confirm:cycleMode': handleToggle, 'confirm:toggle': handleToggle, }, { context: 'Confirmation' }, ) const title = ( Fast mode (research preview) ) return ( exitState.pending ? ( Press {exitState.keyName} again to exit ) : isUnavailable ? ( Esc to cancel ) : ( Tab to toggle · Enter to confirm · Esc to cancel ) } > {unavailableReason ? ( {unavailableReason} ) : ( <> Fast mode {enableFastMode ? 'ON ' : 'OFF'} {pricing} {isCooldown && runtimeState.status === 'cooldown' && ( {runtimeState.reason === 'overloaded' ? 'Fast mode overloaded and is temporarily unavailable' : "You've hit your fast limit"} {' · resets in '} {formatDuration(runtimeState.resetAt - Date.now(), { hideTrailingZeros: true, })} )} )} Learn more:{' '} https://code.claude.com/docs/en/fast-mode ) } async function handleFastModeShortcut( enable: boolean, getAppState: () => AppState, setAppState: (f: (prev: AppState) => AppState) => void, ): Promise { const unavailableReason = getFastModeUnavailableReason() if (unavailableReason) { return `Fast mode unavailable: ${unavailableReason}` } const { mainLoopModel } = getAppState() applyFastMode(enable, setAppState) logEvent('tengu_fast_mode_toggled', { enabled: enable, source: 'shortcut' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }) if (enable) { const fastIcon = getFastIconString(true) const modelUpdated = !isFastModeSupportedByModel(mainLoopModel) ? ` · model set to ${FAST_MODE_MODEL_DISPLAY}` : '' const pricing = formatModelPricing(getOpus46CostTier(true)) return `${fastIcon} Fast mode ON${modelUpdated} · ${pricing}` } else { return `Fast mode OFF` } } export async function call( onDone: LocalJSXCommandOnDone, context: LocalJSXCommandContext, args?: string, ): Promise { if (!isFastModeEnabled()) { return null } // Fetch org fast mode status before showing the picker. We must know // whether the org has disabled fast mode before allowing any toggle. // If a startup prefetch is already in flight, this awaits it. await prefetchFastModeStatus() const arg = args?.trim().toLowerCase() if (arg === 'on' || arg === 'off') { const result = await handleFastModeShortcut( arg === 'on', context.getAppState, context.setAppState, ) onDone(result) return null } const unavailableReason = getFastModeUnavailableReason() logEvent('tengu_fast_mode_picker_shown', { unavailable_reason: (unavailableReason ?? '') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }) return ( ) }