From bdd207a1001446f6504bfc8b137321bfe54766a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Sibiril?= <81782+aureliensibiril@users.noreply.github.com> Date: Mon, 27 Apr 2026 10:03:35 +0200 Subject: [PATCH] Move ErrSuspendForCheckpoint to pkg/agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sentinel is part of the agent cancellation contract — the only caller that needs it (the supervisor) imports pkg/agent already, so keeping it next to SuspendedError prevents the upward dependency that would arise if any future agent.Run caller wanted to trigger graceful suspend. Update pkg/probo/agent_run_handler.go to reference agent.ErrSuspendForCheckpoint. Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com> --- pkg/agent/checkpoint.go | 11 +++++++++++ pkg/probo/agent_run_handler.go | 9 +-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pkg/agent/checkpoint.go b/pkg/agent/checkpoint.go index 840d3d1b3..d78876d3e 100644 --- a/pkg/agent/checkpoint.go +++ b/pkg/agent/checkpoint.go @@ -16,10 +16,21 @@ package agent import ( "context" + "errors" "go.probo.inc/probo/pkg/llm" ) +// ErrSuspendForCheckpoint is the recommended cancel cause for callers +// who want the agent loop to gracefully suspend (build a checkpoint +// and return *SuspendedError) rather than treat the cancellation as a +// silent close. The agent loop only inspects ctx.Err(); any cancel +// cause produces a graceful suspend, but using this sentinel makes +// the intent explicit and lets supervisors distinguish a user-driven +// cancel from infrastructure-level causes (lease loss, heartbeat +// failure) when they inspect context.Cause(ctx). +var ErrSuspendForCheckpoint = errors.New("agent run: graceful suspend requested") + type ( AgentStatus string diff --git a/pkg/probo/agent_run_handler.go b/pkg/probo/agent_run_handler.go index adc6fd10f..fe21e2742 100644 --- a/pkg/probo/agent_run_handler.go +++ b/pkg/probo/agent_run_handler.go @@ -45,13 +45,6 @@ type agentRunHandler struct { var ( _ worker.Handler[coredata.AgentRun] = (*agentRunHandler)(nil) _ worker.StaleRecoverer = (*agentRunHandler)(nil) - - // ErrSuspendForCheckpoint is the cancel cause used when the - // supervisor asks an in-flight run to gracefully suspend so it can - // checkpoint and exit. The agent loop sees ctx.Err() at its next - // turn boundary and returns *SuspendedError; executeRun treats - // that outcome as a graceful exit (no row-status commit). - ErrSuspendForCheckpoint = errors.New("agent run: graceful suspend requested") ) // Claim loads the next pending agent run, marks it RUNNING with a lease @@ -114,7 +107,7 @@ func (h *agentRunHandler) Process(ctx context.Context, run coredata.AgentRun) er go func() { select { case <-h.shutdownCh: - cancelRun(ErrSuspendForCheckpoint) + cancelRun(agent.ErrSuspendForCheckpoint) case <-forwarderDone: } }()