π File detail
utils/planModeV2.ts
π― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes getPlanModeV2AgentCount, getPlanModeV2ExploreAgentCount, isPlanModeInterviewPhaseEnabled, PewterLedgerVariant, and getPewterLedgerVariant β mainly functions, hooks, or classes. It composes internal code from services, auth, and envUtils (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js' import { getRateLimitTier, getSubscriptionType } from './auth.js' import { isEnvDefinedFalsy, isEnvTruthy } from './envUtils.js' export function getPlanModeV2AgentCount(): number {
π€ Exports (heuristic)
getPlanModeV2AgentCountgetPlanModeV2ExploreAgentCountisPlanModeInterviewPhaseEnabledPewterLedgerVariantgetPewterLedgerVariant
π₯οΈ Source preview
import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js'
import { getRateLimitTier, getSubscriptionType } from './auth.js'
import { isEnvDefinedFalsy, isEnvTruthy } from './envUtils.js'
export function getPlanModeV2AgentCount(): number {
// Environment variable override takes precedence
if (process.env.CLAUDE_CODE_PLAN_V2_AGENT_COUNT) {
const count = parseInt(process.env.CLAUDE_CODE_PLAN_V2_AGENT_COUNT, 10)
if (!isNaN(count) && count > 0 && count <= 10) {
return count
}
}
const subscriptionType = getSubscriptionType()
const rateLimitTier = getRateLimitTier()
if (
subscriptionType === 'max' &&
rateLimitTier === 'default_claude_max_20x'
) {
return 3
}
if (subscriptionType === 'enterprise' || subscriptionType === 'team') {
return 3
}
return 1
}
export function getPlanModeV2ExploreAgentCount(): number {
if (process.env.CLAUDE_CODE_PLAN_V2_EXPLORE_AGENT_COUNT) {
const count = parseInt(
process.env.CLAUDE_CODE_PLAN_V2_EXPLORE_AGENT_COUNT,
10,
)
if (!isNaN(count) && count > 0 && count <= 10) {
return count
}
}
return 3
}
/**
* Check if plan mode interview phase is enabled.
*
* Config: ant=always_on, external=tengu_plan_mode_interview_phase gate, envVar=true
*/
export function isPlanModeInterviewPhaseEnabled(): boolean {
// Always on for ants
if (process.env.USER_TYPE === 'ant') return true
const env = process.env.CLAUDE_CODE_PLAN_MODE_INTERVIEW_PHASE
if (isEnvTruthy(env)) return true
if (isEnvDefinedFalsy(env)) return false
return getFeatureValue_CACHED_MAY_BE_STALE(
'tengu_plan_mode_interview_phase',
false,
)
}
export type PewterLedgerVariant = 'trim' | 'cut' | 'cap' | null
/**
* tengu_pewter_ledger β plan file structure prompt experiment.
*
* Controls the Phase 4 "Final Plan" bullets in the 5-phase plan mode
* workflow (messages.ts getPlanPhase4Section). 5-phase is 99% of plan
* traffic; interview-phase (ants) is untouched as a reference population.
*
* Arms: null (control), 'trim', 'cut', 'cap' β progressively stricter
* guidance on plan file size.
*
* Baseline (control, 14d ending 2026-03-02, N=26.3M):
* p50 4,906 chars | p90 11,617 | mean 6,207 | 82% Opus 4.6
* Reject rate monotonic with size: 20% at <2K β 50% at 20K+
*
* Primary: session-level Avg Cost (fact__201omjcij85f) β Opus output is
* 5Γ input price so cost is an output-weighted proxy. planLengthChars
* on tengu_plan_exit is the mechanism but NOT the goal β the cap arm
* could shrink the plan file while increasing total output via
* writeβcountβedit cycles.
* Guardrail: feedback-bad rate, requests/session (too-thin plans β
* more implementation iterations), tool error rate
*/
export function getPewterLedgerVariant(): PewterLedgerVariant {
const raw = getFeatureValue_CACHED_MAY_BE_STALE<string | null>(
'tengu_pewter_ledger',
null,
)
if (raw === 'trim' || raw === 'cut' || raw === 'cap') return raw
return null
}