( currentContext: ToolPermissionContext, // Runtime AppState.fastMode — passed from callers with AppState access so // the disableFastMode circuit breaker reads current state, not stale // settings.fastMode (which is intentionally sticky across /model auto- // downgrades). Optional for callers without AppState (e.g. SDK init paths). fastMode?: boolean, )
| 1076 | * kicking the user out of a mode they've already left during the await. |
| 1077 | */ |
| 1078 | export async function verifyAutoModeGateAccess( |
| 1079 | currentContext: ToolPermissionContext, |
| 1080 | // Runtime AppState.fastMode — passed from callers with AppState access so |
| 1081 | // the disableFastMode circuit breaker reads current state, not stale |
| 1082 | // settings.fastMode (which is intentionally sticky across /model auto- |
| 1083 | // downgrades). Optional for callers without AppState (e.g. SDK init paths). |
| 1084 | fastMode?: boolean, |
| 1085 | ): Promise<AutoModeGateCheckResult> { |
| 1086 | // Auto-mode config — runs in ALL builds (circuit breaker, carousel, kick-out) |
| 1087 | // Fresh read of tengu_auto_mode_config.enabled — this async check runs once |
| 1088 | // after GrowthBook initialization and is the authoritative source for |
| 1089 | // isAutoModeAvailable. The sync startup path uses stale cache; this |
| 1090 | // corrects it. Circuit breaker (enabled==='disabled') takes effect here. |
| 1091 | const autoModeConfig = await getDynamicConfig_BLOCKS_ON_INIT<{ |
| 1092 | enabled?: AutoModeEnabledState |
| 1093 | disableFastMode?: boolean |
| 1094 | }>('tengu_auto_mode_config', {}) |
| 1095 | const enabledState = parseAutoModeEnabledState(autoModeConfig?.enabled) |
| 1096 | const disabledBySettings = isAutoModeDisabledBySettings() |
| 1097 | // Treat settings-disable the same as GrowthBook 'disabled' for circuit-breaker |
| 1098 | // semantics — blocks SDK/explicit re-entry via isAutoModeGateEnabled(). |
| 1099 | autoModeStateModule?.setAutoModeCircuitBroken( |
| 1100 | enabledState === 'disabled' || disabledBySettings, |
| 1101 | ) |
| 1102 | |
| 1103 | // Carousel availability: not circuit-broken, not disabled-by-settings, |
| 1104 | // model supports it, disableFastMode breaker not firing, and (enabled or opted-in) |
| 1105 | const mainModel = getMainLoopModel() |
| 1106 | // Temp circuit breaker: tengu_auto_mode_config.disableFastMode blocks auto |
| 1107 | // mode when fast mode is on. Checks runtime AppState.fastMode (if provided) |
| 1108 | // and, for ants, model name '-fast' substring (ant-internal fast models |
| 1109 | // like capybara-v2-fast[1m] encode speed in the model ID itself). |
| 1110 | // Remove once auto+fast mode interaction is validated. |
| 1111 | const disableFastModeBreakerFires = |
| 1112 | !!autoModeConfig?.disableFastMode && |
| 1113 | (!!fastMode || |
| 1114 | (process.env.USER_TYPE === 'ant' && |
| 1115 | mainModel.toLowerCase().includes('-fast'))) |
| 1116 | const modelSupported = |
| 1117 | modelSupportsAutoMode(mainModel) && !disableFastModeBreakerFires |
| 1118 | let carouselAvailable = false |
| 1119 | if (enabledState !== 'disabled' && !disabledBySettings && modelSupported) { |
| 1120 | carouselAvailable = |
| 1121 | enabledState === 'enabled' || hasAutoModeOptInAnySource() |
| 1122 | } |
| 1123 | // canEnterAuto gates explicit entry (--permission-mode auto, defaultMode: auto) |
| 1124 | // — explicit entry IS an opt-in, so we only block on circuit breaker + settings + model |
| 1125 | const canEnterAuto = |
| 1126 | enabledState !== 'disabled' && !disabledBySettings && modelSupported |
| 1127 | logForDebugging( |
| 1128 | `[auto-mode] verifyAutoModeGateAccess: enabledState=${enabledState} disabledBySettings=${disabledBySettings} model=${mainModel} modelSupported=${modelSupported} disableFastModeBreakerFires=${disableFastModeBreakerFires} carouselAvailable=${carouselAvailable} canEnterAuto=${canEnterAuto}`, |
| 1129 | ) |
| 1130 | |
| 1131 | // Capture CLI-flag intent now (doesn't depend on context). |
| 1132 | const autoModeFlagCli = autoModeStateModule?.getAutoModeFlagCli() ?? false |
| 1133 | |
| 1134 | // Return a transform function that re-evaluates context-dependent conditions |
| 1135 | // against the CURRENT context at setAppState time. The async GrowthBook |
no test coverage detected