mirror of
https://github.com/codeaashu/claude-code.git
synced 2026-04-09 06:38:46 +03:00
claude-code
This commit is contained in:
93
src/tools/FileReadTool/limits.ts
Normal file
93
src/tools/FileReadTool/limits.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Read tool output limits. Two caps apply to text reads:
|
||||
*
|
||||
* | limit | default | checks | cost | on overflow |
|
||||
* |---------------|---------|---------------------------|---------------|-----------------|
|
||||
* | maxSizeBytes | 256 KB | TOTAL FILE SIZE (not out) | 1 stat | throws pre-read |
|
||||
* | maxTokens | 25000 | actual output tokens | API roundtrip | throws post-read|
|
||||
*
|
||||
* Known mismatch: maxSizeBytes gates on total file size, not the slice.
|
||||
* Tested truncating instead of throwing for explicit-limit reads that
|
||||
* exceed the byte cap (#21841, Mar 2026). Reverted: tool error rate
|
||||
* dropped but mean tokens rose — the throw path yields a ~100-byte error
|
||||
* tool-result while truncation yields ~25K tokens of content at the cap.
|
||||
*/
|
||||
import memoize from 'lodash-es/memoize.js'
|
||||
import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js'
|
||||
import { MAX_OUTPUT_SIZE } from 'src/utils/file.js'
|
||||
export const DEFAULT_MAX_OUTPUT_TOKENS = 25000
|
||||
|
||||
/**
|
||||
* Env var override for max output tokens. Returns undefined when unset/invalid
|
||||
* so the caller can fall through to the next precedence tier.
|
||||
*/
|
||||
function getEnvMaxTokens(): number | undefined {
|
||||
const override = process.env.CLAUDE_CODE_FILE_READ_MAX_OUTPUT_TOKENS
|
||||
if (override) {
|
||||
const parsed = parseInt(override, 10)
|
||||
if (!isNaN(parsed) && parsed > 0) {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export type FileReadingLimits = {
|
||||
maxTokens: number
|
||||
maxSizeBytes: number
|
||||
includeMaxSizeInPrompt?: boolean
|
||||
targetedRangeNudge?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Default limits for Read tool when the ToolUseContext doesn't supply an
|
||||
* override. Memoized so the GrowthBook value is fixed at first call — avoids
|
||||
* the cap changing mid-session as the flag refreshes in the background.
|
||||
*
|
||||
* Precedence for maxTokens: env var > GrowthBook > DEFAULT_MAX_OUTPUT_TOKENS.
|
||||
* (Env var is a user-set override, should beat experiment infrastructure.)
|
||||
*
|
||||
* Defensive: each field is individually validated; invalid values fall
|
||||
* through to the hardcoded defaults (no route to cap=0).
|
||||
*/
|
||||
export const getDefaultFileReadingLimits = memoize((): FileReadingLimits => {
|
||||
const override =
|
||||
getFeatureValue_CACHED_MAY_BE_STALE<Partial<FileReadingLimits> | null>(
|
||||
'tengu_amber_wren',
|
||||
{},
|
||||
)
|
||||
|
||||
const maxSizeBytes =
|
||||
typeof override?.maxSizeBytes === 'number' &&
|
||||
Number.isFinite(override.maxSizeBytes) &&
|
||||
override.maxSizeBytes > 0
|
||||
? override.maxSizeBytes
|
||||
: MAX_OUTPUT_SIZE
|
||||
|
||||
const envMaxTokens = getEnvMaxTokens()
|
||||
const maxTokens =
|
||||
envMaxTokens ??
|
||||
(typeof override?.maxTokens === 'number' &&
|
||||
Number.isFinite(override.maxTokens) &&
|
||||
override.maxTokens > 0
|
||||
? override.maxTokens
|
||||
: DEFAULT_MAX_OUTPUT_TOKENS)
|
||||
|
||||
const includeMaxSizeInPrompt =
|
||||
typeof override?.includeMaxSizeInPrompt === 'boolean'
|
||||
? override.includeMaxSizeInPrompt
|
||||
: undefined
|
||||
|
||||
const targetedRangeNudge =
|
||||
typeof override?.targetedRangeNudge === 'boolean'
|
||||
? override.targetedRangeNudge
|
||||
: undefined
|
||||
|
||||
return {
|
||||
maxSizeBytes,
|
||||
maxTokens,
|
||||
includeMaxSizeInPrompt,
|
||||
targetedRangeNudge,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user