diff --git a/CHANGELOG.md b/CHANGELOG.md index cd8acb506..167b7ab67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ Only write entries that are worth mentioning to users. ## Unreleased +- Config: Add `reserved_context_size` setting to customize auto-compaction trigger threshold (default: 50000 tokens) + ## 0.81 (2026-01-21) - Skills: Add flow skill type with embedded Agent Flow (Mermaid/D2) in SKILL.md, invoked via `/flow:` commands diff --git a/docs/en/configuration/config-files.md b/docs/en/configuration/config-files.md index 43fceac90..3ca6c043b 100644 --- a/docs/en/configuration/config-files.md +++ b/docs/en/configuration/config-files.md @@ -52,6 +52,7 @@ max_context_size = 262144 max_steps_per_turn = 100 max_retries_per_step = 3 max_ralph_iterations = 0 +reserved_context_size = 50000 [services.moonshot_search] base_url = "https://api.kimi.com/coding/v1/search" @@ -117,6 +118,7 @@ capabilities = ["thinking", "image_in"] | `max_steps_per_turn` | `integer` | `100` | Maximum steps per turn (alias: `max_steps_per_run`) | | `max_retries_per_step` | `integer` | `3` | Maximum retries per step | | `max_ralph_iterations` | `integer` | `0` | Extra iterations after each user message; `0` disables; `-1` is unlimited | +| `reserved_context_size` | `integer` | `50000` | Reserved token count for LLM response generation; auto-compaction triggers when `context_tokens + reserved_context_size >= max_context_size` | ### `services` diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md index a4924e7cc..be6e82ca0 100644 --- a/docs/en/release-notes/changelog.md +++ b/docs/en/release-notes/changelog.md @@ -4,6 +4,8 @@ This page documents the changes in each Kimi CLI release. ## Unreleased +- Config: Add `reserved_context_size` setting to customize auto-compaction trigger threshold (default: 50000 tokens) + ## 0.81 (2026-01-21) - Skills: Add flow skill type with embedded Agent Flow (Mermaid/D2) in SKILL.md, invoked via `/flow:` commands diff --git a/docs/zh/configuration/config-files.md b/docs/zh/configuration/config-files.md index 7f61f8dce..a602eb734 100644 --- a/docs/zh/configuration/config-files.md +++ b/docs/zh/configuration/config-files.md @@ -52,6 +52,7 @@ max_context_size = 262144 max_steps_per_turn = 100 max_retries_per_step = 3 max_ralph_iterations = 0 +reserved_context_size = 50000 [services.moonshot_search] base_url = "https://api.kimi.com/coding/v1/search" @@ -117,6 +118,7 @@ capabilities = ["thinking", "image_in"] | `max_steps_per_turn` | `integer` | `100` | 单轮最大步数(别名:`max_steps_per_run`) | | `max_retries_per_step` | `integer` | `3` | 单步最大重试次数 | | `max_ralph_iterations` | `integer` | `0` | 每个 User 消息后额外自动迭代次数;`0` 表示关闭;`-1` 表示无限 | +| `reserved_context_size` | `integer` | `50000` | 预留给 LLM 响应生成的 token 数量;当 `context_tokens + reserved_context_size >= max_context_size` 时自动触发压缩 | ### `services` diff --git a/docs/zh/release-notes/changelog.md b/docs/zh/release-notes/changelog.md index 002b38a9b..4c54e936d 100644 --- a/docs/zh/release-notes/changelog.md +++ b/docs/zh/release-notes/changelog.md @@ -4,6 +4,8 @@ ## 未发布 +- Config:添加 `reserved_context_size` 配置项,自定义自动压缩触发阈值(默认 50000 tokens) + ## 0.81 (2026-01-21) - Skills:添加 Flow Skill 类型,在 SKILL.md 中内嵌 Agent Flow(Mermaid/D2),通过 `/flow:` 命令调用 diff --git a/src/kimi_cli/config.py b/src/kimi_cli/config.py index be0f0a54d..07efe82b1 100644 --- a/src/kimi_cli/config.py +++ b/src/kimi_cli/config.py @@ -55,6 +55,9 @@ class LoopControl(BaseModel): """Maximum number of retries in one step""" max_ralph_iterations: int = Field(default=0, ge=-1) """Extra iterations after the first turn in Ralph mode. Use -1 for unlimited.""" + reserved_context_size: int = Field(default=50_000, ge=1000) + """Reserved token count for LLM response generation. Auto-compaction triggers when + context_tokens + reserved_context_size >= max_context_size. Default is 50000.""" class MoonshotSearchConfig(BaseModel): diff --git a/src/kimi_cli/soul/kimisoul.py b/src/kimi_cli/soul/kimisoul.py index c46bb55ba..848c10145 100644 --- a/src/kimi_cli/soul/kimisoul.py +++ b/src/kimi_cli/soul/kimisoul.py @@ -61,8 +61,6 @@ def type_check(soul: KimiSoul): _: Soul = soul -RESERVED_TOKENS = 50_000 - SKILL_COMMAND_PREFIX = "skill:" FLOW_COMMAND_PREFIX = "flow:" DEFAULT_MAX_FLOW_MOVES = 1000 @@ -110,9 +108,6 @@ def __init__( self._context = context self._loop_control = agent.runtime.config.loop_control self._compaction = SimpleCompaction() # TODO: maybe configurable and composable - self._reserved_tokens = RESERVED_TOKENS - if self._runtime.llm is not None: - assert self._reserved_tokens <= self._runtime.llm.max_context_size for tool in agent.toolset.tools: if tool.name == SendDMail_NAME: @@ -348,10 +343,8 @@ async def _pipe_approval_to_wire(): step_outcome: StepOutcome | None = None try: # compact the context if needed - if ( - self._context.token_count + self._reserved_tokens - >= self._runtime.llm.max_context_size - ): + reserved = self._loop_control.reserved_context_size + if self._context.token_count + reserved >= self._runtime.llm.max_context_size: logger.info("Context too long, compacting...") await self.compact_context() diff --git a/tests/test_config.py b/tests/test_config.py index 75e24f0ab..4f81f7093 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -37,6 +37,7 @@ def test_default_config_dump(): "max_steps_per_turn": 100, "max_retries_per_step": 3, "max_ralph_iterations": 0, + "reserved_context_size": 50000, }, "services": {"moonshot_search": None, "moonshot_fetch": None}, "mcp": {"client": {"tool_call_timeout_ms": 60000}}, @@ -62,3 +63,13 @@ def test_load_config_text_invalid(): def test_load_config_invalid_ralph_iterations(): with pytest.raises(ConfigError, match="max_ralph_iterations"): load_config_from_string('{"loop_control": {"max_ralph_iterations": -2}}') + + +def test_load_config_reserved_context_size(): + config = load_config_from_string('{"loop_control": {"reserved_context_size": 30000}}') + assert config.loop_control.reserved_context_size == 30000 + + +def test_load_config_reserved_context_size_too_low(): + with pytest.raises(ConfigError, match="reserved_context_size"): + load_config_from_string('{"loop_control": {"reserved_context_size": 500}}')