import * as React from 'react'; import { useMainLoopModel } from '../../hooks/useMainLoopModel.js'; import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, } from '../../services/analytics/index.js'; import { useAppState, useSetAppState } from '../../state/AppState.js'; import type { LocalJSXCommandOnDone } from '../../types/command.js'; import { type EffortValue, getDisplayedEffortLevel, getEffortEnvOverride, getEffortValueDescription, isEffortLevel, toPersistableEffort, } from '../../utils/effort.js'; import { updateSettingsForSource } from '../../utils/settings/settings.js'; const COMMON_HELP_ARGS = ['help', '-h', '--help']; type EffortCommandResult = { message: string; effortUpdate?: { value: EffortValue | undefined }; }; function setEffortValue(effortValue: EffortValue): EffortCommandResult { const persistable = toPersistableEffort(effortValue); if (persistable !== undefined) { const result = updateSettingsForSource('userSettings', { effortLevel: persistable, }); if (result.error) { return { message: `Failed to set effort level: ${result.error.message}`, }; } } logEvent('tengu_effort_command', { effort: effortValue as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }); // Env var wins at resolveAppliedEffort time. Only flag it when it actually // conflicts — if env matches what the user just asked for, the outcome is // the same, so "Set effort to X" is true and the note is noise. const envOverride = getEffortEnvOverride(); if (envOverride !== undefined && envOverride !== effortValue) { const envRaw = process.env.CLAUDE_CODE_EFFORT_LEVEL; if (persistable === undefined) { return { message: `Not applied: CLAUDE_CODE_EFFORT_LEVEL=${envRaw} overrides effort this session, and ${effortValue} is session-only (nothing saved)`, effortUpdate: { value: effortValue }, }; } return { message: `CLAUDE_CODE_EFFORT_LEVEL=${envRaw} overrides this session — clear it and ${effortValue} takes over`, effortUpdate: { value: effortValue }, }; } const description = getEffortValueDescription(effortValue); const suffix = persistable !== undefined ? '' : ' (this session only)'; return { message: `Set effort level to ${effortValue}${suffix}: ${description}`, effortUpdate: { value: effortValue }, }; } export function showCurrentEffort(appStateEffort: EffortValue | undefined, model: string): EffortCommandResult { const envOverride = getEffortEnvOverride(); const effectiveValue = envOverride === null ? undefined : (envOverride ?? appStateEffort); if (effectiveValue === undefined) { const level = getDisplayedEffortLevel(model, appStateEffort); return { message: `Effort level: auto (currently ${level})` }; } const description = getEffortValueDescription(effectiveValue); return { message: `Current effort level: ${effectiveValue} (${description})`, }; } function unsetEffortLevel(): EffortCommandResult { const result = updateSettingsForSource('userSettings', { effortLevel: undefined, }); if (result.error) { return { message: `Failed to set effort level: ${result.error.message}`, }; } logEvent('tengu_effort_command', { effort: 'auto' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }); // env=auto/unset (null) matches what /effort auto asks for, so only warn // when env is pinning a specific level that will keep overriding. const envOverride = getEffortEnvOverride(); if (envOverride !== undefined && envOverride !== null) { const envRaw = process.env.CLAUDE_CODE_EFFORT_LEVEL; return { message: `Cleared effort from settings, but CLAUDE_CODE_EFFORT_LEVEL=${envRaw} still controls this session`, effortUpdate: { value: undefined }, }; } return { message: 'Effort level set to auto', effortUpdate: { value: undefined }, }; } export function executeEffort(args: string): EffortCommandResult { const normalized = args.toLowerCase(); if (normalized === 'auto' || normalized === 'unset') { return unsetEffortLevel(); } if (!isEffortLevel(normalized)) { return { message: `Invalid argument: ${args}. Valid options are: low, medium, high, max, auto`, }; } return setEffortValue(normalized); } function ShowCurrentEffort({ onDone }: { onDone: (result: string) => void }): React.ReactNode { const effortValue = useAppState(s => s.effortValue); const model = useMainLoopModel(); const { message } = showCurrentEffort(effortValue, model); onDone(message); return null; } function ApplyEffortAndClose({ result, onDone, }: { result: EffortCommandResult; onDone: (result: string) => void; }): React.ReactNode { const setAppState = useSetAppState(); const { effortUpdate, message } = result; React.useEffect(() => { if (effortUpdate) { setAppState(prev => ({ ...prev, effortValue: effortUpdate.value, })); } onDone(message); }, [setAppState, effortUpdate, message, onDone]); return null; } export async function call(onDone: LocalJSXCommandOnDone, _context: unknown, args?: string): Promise { args = args?.trim() || ''; if (COMMON_HELP_ARGS.includes(args)) { onDone( 'Usage: /effort [low|medium|high|xhigh|max|auto]\n\nEffort levels:\n- low: Quick, straightforward implementation\n- medium: Balanced approach with standard testing\n- high: Comprehensive implementation with extensive testing\n- xhigh: Extended reasoning beyond high, short of max; including ChatGPT Codex models\n- max: Maximum capability with deepest reasoning; maps to xhigh for ChatGPT Codex models\n- auto: Use the default effort level for your model', ); return; } if (!args || args === 'current' || args === 'status') { return ; } const result = executeEffort(args); return ; }