source dump of claude code
at main 145 lines 5.6 kB view raw
1import type { BetaUsage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs' 2import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js' 3import { shouldIncludeFirstPartyOnlyBetas } from './betas.js' 4import { isEnvTruthy } from './envUtils.js' 5import { getInitialSettings } from './settings/settings.js' 6 7// The SDK does not yet have types for advisor blocks. 8// TODO(hackyon): Migrate to the real anthropic SDK types when this feature ships publicly 9export type AdvisorServerToolUseBlock = { 10 type: 'server_tool_use' 11 id: string 12 name: 'advisor' 13 input: { [key: string]: unknown } 14} 15 16export type AdvisorToolResultBlock = { 17 type: 'advisor_tool_result' 18 tool_use_id: string 19 content: 20 | { 21 type: 'advisor_result' 22 text: string 23 } 24 | { 25 type: 'advisor_redacted_result' 26 encrypted_content: string 27 } 28 | { 29 type: 'advisor_tool_result_error' 30 error_code: string 31 } 32} 33 34export type AdvisorBlock = AdvisorServerToolUseBlock | AdvisorToolResultBlock 35 36export function isAdvisorBlock(param: { 37 type: string 38 name?: string 39}): param is AdvisorBlock { 40 return ( 41 param.type === 'advisor_tool_result' || 42 (param.type === 'server_tool_use' && param.name === 'advisor') 43 ) 44} 45 46type AdvisorConfig = { 47 enabled?: boolean 48 canUserConfigure?: boolean 49 baseModel?: string 50 advisorModel?: string 51} 52 53function getAdvisorConfig(): AdvisorConfig { 54 return getFeatureValue_CACHED_MAY_BE_STALE<AdvisorConfig>( 55 'tengu_sage_compass', 56 {}, 57 ) 58} 59 60export function isAdvisorEnabled(): boolean { 61 if (isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_ADVISOR_TOOL)) { 62 return false 63 } 64 // The advisor beta header is first-party only (Bedrock/Vertex 400 on it). 65 if (!shouldIncludeFirstPartyOnlyBetas()) { 66 return false 67 } 68 return getAdvisorConfig().enabled ?? false 69} 70 71export function canUserConfigureAdvisor(): boolean { 72 return isAdvisorEnabled() && (getAdvisorConfig().canUserConfigure ?? false) 73} 74 75export function getExperimentAdvisorModels(): 76 | { baseModel: string; advisorModel: string } 77 | undefined { 78 const config = getAdvisorConfig() 79 return isAdvisorEnabled() && 80 !canUserConfigureAdvisor() && 81 config.baseModel && 82 config.advisorModel 83 ? { baseModel: config.baseModel, advisorModel: config.advisorModel } 84 : undefined 85} 86 87// @[MODEL LAUNCH]: Add the new model if it supports the advisor tool. 88// Checks whether the main loop model supports calling the advisor tool. 89export function modelSupportsAdvisor(model: string): boolean { 90 const m = model.toLowerCase() 91 return ( 92 m.includes('opus-4-6') || 93 m.includes('sonnet-4-6') || 94 process.env.USER_TYPE === 'ant' 95 ) 96} 97 98// @[MODEL LAUNCH]: Add the new model if it can serve as an advisor model. 99export function isValidAdvisorModel(model: string): boolean { 100 const m = model.toLowerCase() 101 return ( 102 m.includes('opus-4-6') || 103 m.includes('sonnet-4-6') || 104 process.env.USER_TYPE === 'ant' 105 ) 106} 107 108export function getInitialAdvisorSetting(): string | undefined { 109 if (!isAdvisorEnabled()) { 110 return undefined 111 } 112 return getInitialSettings().advisorModel 113} 114 115export function getAdvisorUsage( 116 usage: BetaUsage, 117): Array<BetaUsage & { model: string }> { 118 const iterations = usage.iterations as 119 | Array<{ type: string }> 120 | null 121 | undefined 122 if (!iterations) { 123 return [] 124 } 125 return iterations.filter( 126 it => it.type === 'advisor_message', 127 ) as unknown as Array<BetaUsage & { model: string }> 128} 129 130export const ADVISOR_TOOL_INSTRUCTIONS = `# Advisor Tool 131 132You have access to an \`advisor\` tool backed by a stronger reviewer model. It takes NO parameters -- when you call it, your entire conversation history is automatically forwarded. The advisor sees the task, every tool call you've made, every result you've seen. 133 134Call advisor BEFORE substantive work -- before writing code, before committing to an interpretation, before building on an assumption. If the task requires orientation first (finding files, reading code, seeing what's there), do that, then call advisor. Orientation is not substantive work. Writing, editing, and declaring an answer are. 135 136Also call advisor: 137- When you believe the task is complete. BEFORE this call, make your deliverable durable: write the file, stage the change, save the result. The advisor call takes time; if the session ends during it, a durable result persists and an unwritten one doesn't. 138- When stuck -- errors recurring, approach not converging, results that don't fit. 139- When considering a change of approach. 140 141On tasks longer than a few steps, call advisor at least once before committing to an approach and once before declaring done. On short reactive tasks where the next action is dictated by tool output you just read, you don't need to keep calling -- the advisor adds most of its value on the first call, before the approach crystallizes. 142 143Give the advice serious weight. If you follow a step and it fails empirically, or you have primary-source evidence that contradicts a specific claim (the file says X, the code does Y), adapt. A passing self-test is not evidence the advice is wrong -- it's evidence your test doesn't check what the advice is checking. 144 145If you've already retrieved data pointing one way and the advisor points another: don't silently switch. Surface the conflict in one more advisor call -- "I found X, you suggest Y, which constraint breaks the tie?" The advisor saw your evidence but may have underweighted it; a reconcile call is cheaper than committing to the wrong branch.`