claude-code/commands/fast/fast.tsx

269 lines
33 KiB
TypeScript
Raw Permalink Normal View History

import { c as _c } from "react/compiler-runtime";
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(t0) {
const $ = _c(30);
const {
onDone,
unavailableReason
} = t0;
const model = useAppState(_temp);
const initialFastMode = useAppState(_temp2);
const setAppState = useSetAppState();
const [enableFastMode, setEnableFastMode] = useState(initialFastMode ?? false);
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = getFastModeRuntimeState();
$[0] = t1;
} else {
t1 = $[0];
}
const runtimeState = t1;
const isCooldown = runtimeState.status === "cooldown";
const isUnavailable = unavailableReason !== null;
let t2;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t2 = formatModelPricing(getOpus46CostTier(true));
$[1] = t2;
} else {
t2 = $[1];
}
const pricing = t2;
let t3;
if ($[2] !== enableFastMode || $[3] !== isUnavailable || $[4] !== model || $[5] !== onDone || $[6] !== setAppState) {
t3 = function handleConfirm() {
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(_temp3);
onDone("Fast mode OFF");
}
};
$[2] = enableFastMode;
$[3] = isUnavailable;
$[4] = model;
$[5] = onDone;
$[6] = setAppState;
$[7] = t3;
} else {
t3 = $[7];
}
const handleConfirm = t3;
let t4;
if ($[8] !== initialFastMode || $[9] !== isUnavailable || $[10] !== onDone || $[11] !== setAppState) {
t4 = function handleCancel() {
if (isUnavailable) {
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"
});
};
$[8] = initialFastMode;
$[9] = isUnavailable;
$[10] = onDone;
$[11] = setAppState;
$[12] = t4;
} else {
t4 = $[12];
}
const handleCancel = t4;
let t5;
if ($[13] !== isUnavailable) {
t5 = function handleToggle() {
if (isUnavailable) {
return;
}
setEnableFastMode(_temp4);
};
$[13] = isUnavailable;
$[14] = t5;
} else {
t5 = $[14];
}
const handleToggle = t5;
let t6;
if ($[15] !== handleConfirm || $[16] !== handleToggle) {
t6 = {
"confirm:yes": handleConfirm,
"confirm:nextField": handleToggle,
"confirm:next": handleToggle,
"confirm:previous": handleToggle,
"confirm:cycleMode": handleToggle,
"confirm:toggle": handleToggle
};
$[15] = handleConfirm;
$[16] = handleToggle;
$[17] = t6;
} else {
t6 = $[17];
}
let t7;
if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
t7 = {
context: "Confirmation"
};
$[18] = t7;
} else {
t7 = $[18];
}
useKeybindings(t6, t7);
let t8;
if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
t8 = <Text><FastIcon cooldown={isCooldown} /> Fast mode (research preview)</Text>;
$[19] = t8;
} else {
t8 = $[19];
}
const title = t8;
let t9;
if ($[20] !== isUnavailable) {
t9 = exitState => exitState.pending ? <Text>Press {exitState.keyName} again to exit</Text> : isUnavailable ? <Text>Esc to cancel</Text> : <Text>Tab to toggle · Enter to confirm · Esc to cancel</Text>;
$[20] = isUnavailable;
$[21] = t9;
} else {
t9 = $[21];
}
let t10;
if ($[22] !== enableFastMode || $[23] !== unavailableReason) {
t10 = unavailableReason ? <Box marginLeft={2}><Text color="error">{unavailableReason}</Text></Box> : <><Box flexDirection="column" gap={0} marginLeft={2}><Box flexDirection="row" gap={2}><Text bold={true}>Fast mode</Text><Text color={enableFastMode ? "fastMode" : undefined} bold={enableFastMode}>{enableFastMode ? "ON " : "OFF"}</Text><Text dimColor={true}>{pricing}</Text></Box></Box>{isCooldown && runtimeState.status === "cooldown" && <Box marginLeft={2}><Text color="warning">{runtimeState.reason === "overloaded" ? "Fast mode overloaded and is temporarily unavailable" : "You've hit your fast limit"}{" \xB7 resets in "}{formatDuration(runtimeState.resetAt - Date.now(), {
hideTrailingZeros: true
})}</Text></Box>}</>;
$[22] = enableFastMode;
$[23] = unavailableReason;
$[24] = t10;
} else {
t10 = $[24];
}
let t11;
if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
t11 = <Text dimColor={true}>Learn more:{" "}<Link url="https://code.claude.com/docs/en/fast-mode">https://code.claude.com/docs/en/fast-mode</Link></Text>;
$[25] = t11;
} else {
t11 = $[25];
}
let t12;
if ($[26] !== handleCancel || $[27] !== t10 || $[28] !== t9) {
t12 = <Dialog title={title} subtitle={`High-speed mode for ${FAST_MODE_MODEL_DISPLAY}. Billed as extra usage at a premium rate. Separate rate limits apply.`} onCancel={handleCancel} color="fastMode" inputGuide={t9}>{t10}{t11}</Dialog>;
$[26] = handleCancel;
$[27] = t10;
$[28] = t9;
$[29] = t12;
} else {
t12 = $[29];
}
return t12;
}
function _temp4(prev_0) {
return !prev_0;
}
function _temp3(prev) {
return {
...prev,
fastMode: false
};
}
function _temp2(s_0) {
return s_0.fastMode;
}
function _temp(s) {
return s.mainLoopModel;
}
async function handleFastModeShortcut(enable: boolean, getAppState: () => AppState, setAppState: (f: (prev: AppState) => AppState) => void): Promise<string> {
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<React.ReactNode | null> {
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 <FastModePicker onDone={onDone} unavailableReason={unavailableReason} />;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZVN0YXRlIiwiQ29tbWFuZFJlc3VsdERpc3BsYXkiLCJMb2NhbEpTWENvbW1hbmRDb250ZXh0IiwiRGlhbG9nIiwiRmFzdEljb24iLCJnZXRGYXN0SWNvblN0cmluZyIsIkJveCIsIkxpbmsiLCJUZXh0IiwidXNlS2V5YmluZGluZ3MiLCJBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTIiwibG9nRXZlbnQiLCJBcHBTdGF0ZSIsInVzZUFwcFN0YXRlIiwidXNlU2V0QXBwU3RhdGUiLCJMb2NhbEpTWENvbW1hbmRPbkRvbmUiLCJjbGVhckZhc3RNb2RlQ29vbGRvd24iLCJGQVNUX01PREVfTU9ERUxfRElTUExBWSIsImdldEZhc3RNb2RlTW9kZWwiLCJnZXRGYXN0TW9kZVJ1bnRpbWVTdGF0ZSIsImdldEZhc3RNb2RlVW5hdmFpbGFibGVSZWFzb24iLCJpc0Zhc3RNb2RlRW5hYmxlZCIsImlzRmFzdE1vZGVTdXBwb3J0ZWRCeU1vZGVsIiwicHJlZmV0Y2hGYXN0TW9kZVN0YXR1cyIsImZvcm1hdER1cmF0aW9uIiwiZm9ybWF0TW9kZWxQcmljaW5nIiwiZ2V0T3B1czQ2Q29zdFRpZXIiLCJ1cGRhdGVTZXR0aW5nc0ZvclNvdXJjZSIsImFwcGx5RmFzdE1vZGUiLCJlbmFibGUiLCJzZXRBcHBTdGF0ZSIsImYiLCJwcmV2IiwiZmFzdE1vZGUiLCJ1bmRlZmluZWQiLCJuZWVkc01vZGVsU3dpdGNoIiwibWFpbkxvb3BNb2RlbCIsIm1haW5Mb29wTW9kZWxGb3JTZXNzaW9uIiwiRmFzdE1vZGVQaWNrZXIiLCJ0MCIsIiQiLCJfYyIsIm9uRG9uZSIsInVuYXZhaWxhYmxlUmVhc29uIiwibW9kZWwiLCJfdGVtcCIsImluaXRpYWxGYXN0TW9kZSIsIl90ZW1wMiIsImVuYWJsZUZhc3RNb2RlIiwic2V0RW5hYmxlRmFzdE1vZGUiLCJ0MSIsIlN5bWJvbCIsImZvciIsInJ1bnRpbWVTdGF0ZSIsImlzQ29vbGRvd24iLCJzdGF0dXMiLCJpc1VuYXZhaWxhYmxlIiwidDIiLCJwcmljaW5nIiwidDMiLCJoYW5kbGVDb25maXJtIiwiZW5hYmxlZCIsInNvdXJjZSIsImZhc3RJY29uIiwibW9kZWxVcGRhdGVkIiwiX3RlbXAzIiwidDQiLCJoYW5kbGVDYW5jZWwiLCJkaXNwbGF5IiwibWVzc2FnZSIsInQ1IiwiaGFuZGxlVG9nZ2xlIiwiX3RlbXA0IiwidDYiLCJ0NyIsImNvbnRleHQiLCJ0OCIsInRpdGxlIiwidDkiLCJleGl0U3RhdGUiLCJwZW5kaW5nIiwia2V5TmFtZSIsInQxMCIsInJlYXNvbiIsInJlc2V0QXQiLCJEYXRlIiwibm93IiwiaGlkZVRyYWlsaW5nWmVyb3MiLCJ0MTEiLCJ0MTIiLCJwcmV2XzAiLCJzXzAiLCJzIiwiaGFuZGxlRmFzdE1vZGVTaG9ydGN1dCIsImdldEFwcFN0YXRlIiwiUHJvbWlzZSIsImNhbGwiLCJhcmdzIiwiUmVhY3ROb2RlIiwiYXJnIiwidHJpbSIsInRvTG93ZXJDYXNlIiwicmVzdWx0IiwidW5hdmFpbGFibGVfcmVhc29uIl0sInNvdXJjZXMiOlsiZmFzdC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHR5cGUge1xuICBDb21tYW5kUmVzdWx0RGlzcGxheSxcbiAgTG9jYWxKU1hDb21tYW5kQ29udGV4dCxcbn0gZnJvbSAnLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgeyBEaWFsb2cgfSBmcm9tICcuLi8uLi9jb21wb25lbnRzL2Rlc2lnbi1zeXN0ZW0vRGlhbG9nLmpzJ1xuaW1wb3J0IHsgRmFzdEljb24sIGdldEZhc3RJY29uU3RyaW5nIH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9GYXN0SWNvbi5qcydcbmltcG9ydCB7IEJveCwgTGluaywgVGV4dCB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB7IHVzZUtleWJpbmRpbmdzIH0gZnJvbSAnLi4vLi4va2V5YmluZGluZ3MvdXNlS2V5YmluZGluZy5qcydcbmltcG9ydCB7XG4gIHR5cGUgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgbG9nRXZlbnQsXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FuYWx5dGljcy9pbmRleC5qcydcbmltcG9ydCB7XG4gIHR5cGUgQXBwU3RhdGUsXG4gIHVzZUFwcFN0YXRlLFxuICB1c2VTZXRBcHBTdGF0ZSxcbn0gZnJvbSAnLi4vLi4vc3RhdGUvQXBwU3RhdGUuanMnXG5pbXBvcnQgdHlwZSB7IExvY2FsSlNYQ29tbWFuZE9uRG9uZSB9IGZyb20gJy4uLy4uL3R5cGVzL2NvbW1hbmQuanMnXG5pbXBvcnQge1xuICBjbGVhckZhc3RNb2RlQ29vbGRvd24sXG4gIEZBU1RfTU9ERV9NT0RFTF9ESVNQTEFZLFxuICBnZXRGYXN0TW9kZU1vZGVsLFxuICBnZXRGYXN0TW9kZVJ1bnRpbWVTdGF0ZSxcbiAgZ2V0RmFzdE1vZGVVbmF2YWlsYWJsZVJlYXNvbixcbiAgaXNGYXN0TW9kZUVuYWJsZWQsXG4gIGlzRmFzdE1vZGVTdXBwb3J0ZWRCeU1vZGVsLFxuICBwcmVmZXRjaEZhc3RNb2RlU3RhdHVzLFxufSBmcm9tICcuLi8uLi91dGlscy9mYXN0TW9kZS5qcydcbmltcG9ydCB7IGZvcm1hdER1cmF0aW9uIH0gZnJvbSAnLi4vLi4vdXRpbHMvZm9ybWF0LmpzJ1xuaW1wb3J0IHsgZm9ybWF0TW9kZWxQcmljaW5nLCBnZXRPcHVzNDZDb3N0VGllciB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsQ29zdC5qcydcbmltcG9ydCB7IHVwZGF0ZVNldHRpbmdzRm9yU291cmNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvc2V0dGluZ3Mvc2V0dGluZ3MuanMnXG5cbmZ1bmN0aW9uIGFwcGx5RmFzdE1vZGUoXG4gIGVuYWJsZTogYm9vbGVhbixcbiAgc2V0QXBwU3RhdGU6IChmOiAocHJldjogQXBwU3RhdGUpID0+IEFwcFN0YXRlKSA9PiB2b2lkLFxuKTogdm9pZCB7XG4gIGNsZWFyRmFzdE1vZGVDb29sZG93bigpXG4gIHVwZGF0ZVNldHRpbmdzRm9yU291cmNlKCd1c2VyU2V0dGluZ3MnLCB7XG4gICAgZmFzdE1vZGU6IGVuYWJsZSA/IHRydWUgOiB1bmRlZmluZWQsXG4gIH0pXG4gIGlmIChlbmFibGUpIHtcbiAgICBzZXRBcHBTdGF0ZShwcmV2ID0+IHtcbiAgICAgIC8vIE9ubHkgc3dpdGNoIG1vZGVsIGlmIGN1cnJlbnQgbW9kZWwgZG9lc24ndCBzdXBwb3J0IGZhc3QgbW9kZVxuICAgICAgY29uc3QgbmVlZHNNb2RlbFN3aXRjaCA9ICFpc0Zhc3RNb2RlU3VwcG9