From f23af3b38c3c9f76086e7ec7495079afa2708526 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:28:02 +0000 Subject: [PATCH] fix(coderd/x/chatd/chatloop): remove compaction timeout --- coderd/x/chatd/chatloop/chatloop.go | 1 - coderd/x/chatd/chatloop/compaction.go | 27 ++++------------ .../chatloop/compaction_internal_test.go | 32 ++++++++++++++++++- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/coderd/x/chatd/chatloop/chatloop.go b/coderd/x/chatd/chatloop/chatloop.go index 2086868d9e943..33505aa593bf1 100644 --- a/coderd/x/chatd/chatloop/chatloop.go +++ b/coderd/x/chatd/chatloop/chatloop.go @@ -271,7 +271,6 @@ type GenerateCompactionOptions struct { ContextLimitFallback int64 SummaryPrompt string SystemSummaryPrefix string - Timeout time.Duration StepUsage fantasy.Usage StepMetadata fantasy.ProviderMetadata diff --git a/coderd/x/chatd/chatloop/compaction.go b/coderd/x/chatd/chatloop/compaction.go index 330def364f1f0..946023edb285e 100644 --- a/coderd/x/chatd/chatloop/compaction.go +++ b/coderd/x/chatd/chatloop/compaction.go @@ -20,11 +20,9 @@ const ( maxCompactionThresholdPercent = int32(100) // compactionDebugCreateRunTimeout caps the compaction debug - // CreateRun budget so a slow or locked DB cannot consume the - // compaction's configured Timeout and cause model.Generate to - // fail with deadline exceeded. Debug instrumentation is - // best-effort; running without the debug row is preferable to - // failing the compaction. + // CreateRun budget. Debug instrumentation is best-effort; + // running without the debug row is preferable to blocking + // compaction on a slow or locked DB. compactionDebugCreateRunTimeout = 5 * time.Second defaultCompactionSummaryPrompt = "You are performing a context compaction. " + @@ -54,7 +52,6 @@ const ( defaultCompactionSystemSummaryPrefix = "The following is a summary of " + "the earlier conversation. The assistant was actively working when " + "the context was compacted. Continue the work described below:" - defaultCompactionTimeout = 90 * time.Second ) type CompactionOptions struct { @@ -62,7 +59,6 @@ type CompactionOptions struct { ContextLimit int64 SummaryPrompt string SystemSummaryPrefix string - Timeout time.Duration Persist func(context.Context, CompactionResult) error DebugSvc *chatdebug.Service ChatID uuid.UUID @@ -170,7 +166,6 @@ func normalizedCompactionGenerateConfig(opts GenerateCompactionOptions) (Compact ContextLimit: opts.ContextLimit, SummaryPrompt: opts.SummaryPrompt, SystemSummaryPrefix: opts.SystemSummaryPrefix, - Timeout: opts.Timeout, DebugSvc: opts.DebugSvc, ChatID: opts.ChatID, HistoryTipMessageID: opts.HistoryTipMessageID, @@ -184,9 +179,6 @@ func normalizedCompactionGenerateConfig(opts GenerateCompactionOptions) (Compact if strings.TrimSpace(config.SystemSummaryPrefix) == "" { config.SystemSummaryPrefix = defaultCompactionSystemSummaryPrefix } - if config.Timeout <= 0 { - config.Timeout = defaultCompactionTimeout - } if config.ThresholdPercent < minCompactionThresholdPercent || config.ThresholdPercent > maxCompactionThresholdPercent { config.ThresholdPercent = defaultCompactionThresholdPercent @@ -285,11 +277,9 @@ func startCompactionDebugRun( } // Use a separate short-lived context for the debug insert so a - // slow or locked DB cannot consume the compaction timeout budget - // and turn debug slowness into a compaction failure via - // model.Generate hitting a deadline exceeded. Detached from the - // parent so cancellation of the compaction run still lets the - // insert reach a terminal state, matching the best-effort + // slow or locked DB cannot block the model call. Detached from + // the parent so cancellation of the compaction run still lets + // the insert reach a terminal state, matching the best-effort // contract of debug instrumentation. createRunCtx, createRunCancel := context.WithTimeout( context.WithoutCancel(ctx), compactionDebugCreateRunTimeout, @@ -360,10 +350,7 @@ func generateCompactionSummary( }) toolChoice := fantasy.ToolChoiceNone - summaryCtx, cancel := context.WithTimeout(ctx, options.Timeout) - defer cancel() - - summaryCtx, finishDebugRun := startCompactionDebugRun(summaryCtx, options) + summaryCtx, finishDebugRun := startCompactionDebugRun(ctx, options) defer func() { // If model.Generate (or anything else below) panics, the // named err return is still nil at this point. Without the diff --git a/coderd/x/chatd/chatloop/compaction_internal_test.go b/coderd/x/chatd/chatloop/compaction_internal_test.go index ba6580465d23f..f4f086a69847c 100644 --- a/coderd/x/chatd/chatloop/compaction_internal_test.go +++ b/coderd/x/chatd/chatloop/compaction_internal_test.go @@ -221,7 +221,6 @@ func TestGenerateCompactionSummary_PanicFinalizesAsError(t *testing.T) { DebugSvc: svc, ChatID: chatID, SummaryPrompt: "summarize", - Timeout: time.Second, }) }) @@ -233,3 +232,34 @@ func TestGenerateCompactionSummary_PanicFinalizesAsError(t *testing.T) { t.Fatal("FinalizeRun never reached UpdateChatDebugRun on panic") } } + +func TestGenerateCompactionSummary_UsesCallerContext(t *testing.T) { + t.Parallel() + + type contextKey string + testCtx := context.WithValue(context.Background(), contextKey("key"), "value") + var ctxSeen context.Context + model := &chattest.FakeModel{ + ProviderName: "fake", + GenerateFn: func(ctx context.Context, _ fantasy.Call) (*fantasy.Response, error) { + ctxSeen = ctx + return &fantasy.Response{ + Content: []fantasy.Content{ + fantasy.TextContent{Text: "summary"}, + }, + }, nil + }, + } + + summary, err := generateCompactionSummary(testCtx, model, + []fantasy.Message{textMessage(fantasy.MessageRoleUser, "hello")}, + CompactionOptions{SummaryPrompt: "summarize"}, + ) + require.NoError(t, err) + require.Equal(t, "summary", summary) + require.Same(t, testCtx, ctxSeen) + require.NoError(t, ctxSeen.Err()) + _, ok := ctxSeen.Deadline() + require.False(t, ok) + require.Equal(t, "value", ctxSeen.Value(contextKey("key"))) +}