Pausing and Resuming Agents Through API Calls
Introduction: Adding Lifecycle Control to Agent APIs
In the previous lesson, you implemented database persistence and progress callbacks that save the agent's state after each step. This allows clients to monitor progress in real time, but they still have no control over the agent once it starts running. Now it's time to complete Factor 6 — Launch / Pause / Resume with simple APIs. You already have the launch endpoint from lesson one and the durable persistence layer from lesson two; in this lesson, you add the pause and resume endpoints that give users the power to stop expensive computations temporarily or correct mistakes without losing progress. You will implement these endpoints using a cooperative pause mechanism that lets agents stop gracefully between steps.
How the Pause Mechanism Works
Unlike forcefully terminating a thread or process, a cooperative pause lets the agent finish its current step before stopping. This approach works by having the pause endpoint change the database status field to "paused" and requiring the agent's progress callback to check for this status change after each step completes.
When the callback detects that the status has been changed externally, it updates the local state object to reflect the pause, causing the agent's main loop to exit on its next iteration. The advantage of this design is that it never interrupts the agent mid-step, ensuring the agent's state remains consistent and valid, with all fields properly synchronized. This is exactly what Factor 6 calls for: the agent can checkpoint, wait, and resume reliably across time.
Modifying the Progress Callback to Detect Pause Requests
As a reminder from the previous lesson, the progress callback is called after each agent step to save the current state to the database. To support pause detection, you need to modify this callback to check whether the database status was changed to "paused" by an external request:
The modified callback first queries the database to load the current record and then checks whether db_state.status equals "paused". If it does, the callback recognizes that an external request changed the status and updates the local state.status to "paused" as well. This status change causes the agent's main loop condition, while state.status == "running", to evaluate to False on the next iteration, ending the workflow.
The callback then saves all other fields without overwriting the "paused" status, preserving the pause signal. In the normal case where no pause was requested, the callback updates all fields, including status, maintaining the previous behavior you implemented in the last lesson.
