From 3055d8f46053584eb0408640bf85b96a2e8dccdb Mon Sep 17 00:00:00 2001 From: xgopilot Date: Wed, 15 Apr 2026 14:24:51 +0000 Subject: [PATCH] fix(runtime): guard non-positive resolved auto-compact threshold - fallback when resolver returns zero/negative without error - add regression tests for zero/negative resolver outputs - align compact/config docs with implicit-threshold behavior Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com> --- docs/context-compact.md | 2 +- docs/guides/configuration.md | 2 ++ internal/runtime/run.go | 2 +- internal/runtime/runtime_test.go | 52 ++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/docs/context-compact.md b/docs/context-compact.md index af991d91..86c20a63 100644 --- a/docs/context-compact.md +++ b/docs/context-compact.md @@ -47,7 +47,7 @@ context: - `auto_compact.enabled` 控制是否启用基于 token 阈值的自动压缩;默认关闭。 - `auto_compact.input_token_threshold` - 当会话累计输入 token 数达到此阈值时触发自动压缩;默认 100000。 + 当会话累计输入 token 数达到此阈值时触发自动压缩;默认 `0`(自动推导),推导失败时回退到 `fallback_input_token_threshold`(默认 `100000`)。 ## 自动压缩 diff --git a/docs/guides/configuration.md b/docs/guides/configuration.md index 4a0191e1..c03f3209 100644 --- a/docs/guides/configuration.md +++ b/docs/guides/configuration.md @@ -83,6 +83,8 @@ context: | `context.compact.micro_compact_disabled` | 是否关闭默认启用的 micro compact | | `context.auto_compact.enabled` | 是否启用自动压缩 | | `context.auto_compact.input_token_threshold` | 自动压缩输入 token 阈值 | +| `context.auto_compact.reserve_tokens` | 自动阈值推导时预留 token 缓冲(`resolved_threshold = context_window - reserve_tokens`) | +| `context.auto_compact.fallback_input_token_threshold` | 自动推导失败时使用的保底阈值 | ### `runtime` 字段 diff --git a/internal/runtime/run.go b/internal/runtime/run.go index 93415b36..031eb092 100644 --- a/internal/runtime/run.go +++ b/internal/runtime/run.go @@ -359,7 +359,7 @@ func (s *Service) autoCompactThreshold(ctx context.Context, cfg config.Config) i } if s != nil && s.autoCompactThresholdResolver != nil { threshold, err := s.autoCompactThresholdResolver.ResolveAutoCompactThreshold(ctx, cfg) - if err == nil { + if err == nil && threshold > 0 { return threshold } } diff --git a/internal/runtime/runtime_test.go b/internal/runtime/runtime_test.go index 8ad229d7..a67f70de 100644 --- a/internal/runtime/runtime_test.go +++ b/internal/runtime/runtime_test.go @@ -4297,6 +4297,58 @@ func TestAutoCompactThresholdFallsBackWhenResolverErrors(t *testing.T) { } } +func TestAutoCompactThresholdFallsBackWhenResolverReturnsZeroWithoutError(t *testing.T) { + t.Parallel() + + service := &Service{} + service.SetAutoCompactThresholdResolver(autoCompactThresholdResolverFunc( + func(ctx context.Context, cfg config.Config) (int, error) { + return 0, nil + }, + )) + + cfg := config.Config{ + Context: config.ContextConfig{ + AutoCompact: config.AutoCompactConfig{ + Enabled: true, + InputTokenThreshold: 0, + FallbackInputTokenThreshold: 88000, + }, + }, + } + + threshold := service.autoCompactThreshold(context.Background(), cfg) + if threshold != 88000 { + t.Fatalf("expected fallback threshold == 88000, got %d", threshold) + } +} + +func TestAutoCompactThresholdFallsBackWhenResolverReturnsNegativeWithoutError(t *testing.T) { + t.Parallel() + + service := &Service{} + service.SetAutoCompactThresholdResolver(autoCompactThresholdResolverFunc( + func(ctx context.Context, cfg config.Config) (int, error) { + return -1, nil + }, + )) + + cfg := config.Config{ + Context: config.ContextConfig{ + AutoCompact: config.AutoCompactConfig{ + Enabled: true, + InputTokenThreshold: 0, + FallbackInputTokenThreshold: 88000, + }, + }, + } + + threshold := service.autoCompactThreshold(context.Background(), cfg) + if threshold != 88000 { + t.Fatalf("expected fallback threshold == 88000, got %d", threshold) + } +} + func TestAutoCompactThresholdImplicitModeWithoutResolverUsesFallback(t *testing.T) { t.Parallel()