96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
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
|
||
}
|