Skip to content
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ As long as you have an openai-like endpoint, it should work.
- `/config` - Open configuration panel
- `/cost` - Show token usage and costs
- `/clear` - Clear conversation history
- `/compact-threshold` - View or set auto-compact threshold ratio (e.g. `/compact-threshold 0.85` or `/compact-threshold 85%`)

| Value | Effect | Use Case |
|-------|--------|----------|
| 0.80 | Compress earlier, more conservative | Small context models (e.g. deepseek 131k) |
| 0.85 | Balanced | Medium context models |
| 0.90 | Default | Large context models (e.g. Claude 200k) |

- `/init` - Initialize project context

## Multi-Model Intelligent Collaboration
Expand Down
8 changes: 8 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ Kode 同时使用 `~/.kode` 目录(存放额外数据,如内存文件)和
- `/config` - 打开配置面板
- `/cost` - 显示 token 使用量和成本
- `/clear` - 清除对话历史
- `/compact-threshold` - 查看或设置自动压缩阈值比例(如 `/compact-threshold 0.85` 或 `/compact-threshold 85%`)

| 值 | 效果 | 适用场景 |
|----|------|----------|
| 0.80 | 更早压缩,更保守 | 小上下文模型(如 deepseek 131k) |
| 0.85 | 平衡 | 中等上下文模型 |
| 0.90 | 默认 | 大上下文模型(如 Claude 200k) |

- `/init` - 初始化项目上下文

## 多模型智能协同
Expand Down
91 changes: 91 additions & 0 deletions src/commands/compact-threshold.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import chalk from 'chalk'
import type { Command } from '@commands'
import { getGlobalConfig, saveGlobalConfig } from '@utils/config'
import {
AUTO_COMPACT_THRESHOLD_RATIO,
getAutoCompactThresholdRatio,
isValidAutoCompactThresholdRatio,
} from '@utils/session/autoCompactThreshold'

const HELP_ARGS = new Set(['help', '-h', '--help', '?'])
const RESET_ARGS = new Set(['reset', 'default'])

function parseThresholdInput(raw: string): number | null {
const trimmed = raw.trim()
if (!trimmed) return null

let valueText = trimmed
let isPercent = false

if (valueText.endsWith('%')) {
isPercent = true
valueText = valueText.slice(0, -1).trim()
}

if (!valueText) return null

const value = Number(valueText)
if (!Number.isFinite(value)) return null

let ratio = value
// Treat bare values >1 as percentages (85 => 0.85) while still allowing ratios like 0.85.
if (isPercent || (value > 1 && value <= 100)) {
ratio = value / 100
}

return isValidAutoCompactThresholdRatio(ratio) ? ratio : null
}

function formatRatio(ratio: number): string {
const percent = Math.round(ratio * 100)
return `${ratio} (${percent}%)`
}

const compactThreshold = {
type: 'local',
name: 'compact-threshold',
description: 'View or set the auto-compact threshold ratio',
isEnabled: true,
isHidden: false,
argumentHint: '[ratio]',
userFacingName() {
return 'compact-threshold'
},
async call(args) {
const raw = args.trim()

if (!raw || HELP_ARGS.has(raw)) {
const configured = getGlobalConfig().autoCompactThreshold
const isCustom = isValidAutoCompactThresholdRatio(configured)
const ratio = getAutoCompactThresholdRatio()
const defaultNote = isCustom ? '' : ' (default)'

return [
`Auto-compact threshold: ${formatRatio(ratio)}${defaultNote}`,
'Usage: /compact-threshold 0.85',
'Tip: You can also use percentages, e.g. /compact-threshold 85%',
].join('\n')
}

if (RESET_ARGS.has(raw)) {
const nextConfig = { ...getGlobalConfig() }
delete nextConfig.autoCompactThreshold
saveGlobalConfig(nextConfig)
return `Auto-compact threshold reset to default (${AUTO_COMPACT_THRESHOLD_RATIO}).`
}

const parsed = parseThresholdInput(raw)
if (!parsed) {
return [
`Invalid threshold: ${chalk.bold(raw)}`,
'Provide a ratio greater than 0 and less than 1 (e.g. 0.85 or 85%).',
].join('\n')
}

const config = getGlobalConfig()
saveGlobalConfig({ ...config, autoCompactThreshold: parsed })
return `Auto-compact threshold set to ${formatRatio(parsed)}.`
},
} satisfies Command

export default compactThreshold
2 changes: 2 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import bug from './bug'
import clear from './clear'
import compact from './compact'
import compactThreshold from './compact-threshold'
import config from './config'
import cost from './cost'
import ctxViz from './ctx-viz'
Expand Down Expand Up @@ -92,6 +93,7 @@ const COMMANDS = memoize((): Command[] => [
agents,
clear,
compact,
compactThreshold,
config,
cost,
doctor,
Expand Down
3 changes: 2 additions & 1 deletion src/core/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export type GlobalConfig = {
}
primaryProvider?: ProviderType
maxTokens?: number
autoCompactThreshold?: number
hasAcknowledgedCostThreshold?: boolean
oauthAccount?: AccountInfo
proxy?: string
Expand All @@ -187,6 +188,7 @@ export const GLOBAL_CONFIG_KEYS = [
'primaryProvider',
'preferredNotifChannel',
'maxTokens',
'autoCompactThreshold',
] as const

export type GlobalConfigKey = (typeof GLOBAL_CONFIG_KEYS)[number]
Expand Down Expand Up @@ -214,4 +216,3 @@ export type ProjectMcpServerDefinitions = {
mcpJsonPath: string
mcprcPath: string
}

7 changes: 1 addition & 6 deletions src/utils/session/autoCompactCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { getModelManager } from '@utils/model'
import { debug as debugLogger } from '@utils/log/debugLogger'
import { logError } from '@utils/log'
import {
AUTO_COMPACT_THRESHOLD_RATIO,
calculateAutoCompactThresholds,
} from './autoCompactThreshold'

Expand Down Expand Up @@ -63,11 +62,7 @@ Focus on information essential for continuing the conversation effectively, incl

async function calculateThresholds(tokenCount: number) {
const contextLimit = await getMainConversationContextLimit()
return calculateAutoCompactThresholds(
tokenCount,
contextLimit,
AUTO_COMPACT_THRESHOLD_RATIO,
)
return calculateAutoCompactThresholds(tokenCount, contextLimit)
}

async function shouldAutoCompact(messages: Message[]): Promise<boolean> {
Expand Down
23 changes: 22 additions & 1 deletion src/utils/session/autoCompactThreshold.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
import { getGlobalConfig } from '@utils/config'

export const AUTO_COMPACT_THRESHOLD_RATIO = 0.9

export function isValidAutoCompactThresholdRatio(
value: unknown,
): value is number {
return (
typeof value === 'number' &&
Number.isFinite(value) &&
value > 0 &&
value < 1
)
}

export function getAutoCompactThresholdRatio(): number {
const config = getGlobalConfig()
if (isValidAutoCompactThresholdRatio(config.autoCompactThreshold)) {
return config.autoCompactThreshold
}
return AUTO_COMPACT_THRESHOLD_RATIO
}

export function calculateAutoCompactThresholds(
tokenCount: number,
contextLimit: number,
ratio: number = AUTO_COMPACT_THRESHOLD_RATIO,
ratio: number = getAutoCompactThresholdRatio(),
): {
isAboveAutoCompactThreshold: boolean
percentUsed: number
Expand Down
Loading