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: } }()