> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Breakpoint and Continue

> Demonstrates pausing a workflow for human review then resuming execution with preserved workflow state using interrupt and resume primitives

This lesson demonstrates a common human-in-the-loop interruption pattern for workflows: instead of running end-to-end automatically, a workflow pauses at a breakpoint, waits for a human decision (review/approval), and then continues from the same logical point. The example below simulates this behavior with plain Python to keep it simple and portable. It mirrors how breakpoints and interrupts behave in workflow runtimes while remaining runtime-agnostic.

<Callout icon="lightbulb" color="#1CB2FE">
  This example demonstrates the pattern and data flow used for breakpoints. In a real deployment the interrupt/continue primitives would be provided by the platform runtime.
</Callout>

## Overview

The demo implements a lightweight pattern that:

1. Generates content.
2. Interrupts execution and returns an interrupt payload for human review.
3. Resumes execution using the reviewer’s decision and updates the workflow state.

Key concepts used:

* Breakpoint / Interrupt: the point where the workflow pauses and returns a payload for review.
* Resume: receiving an external decision and continuing execution from the same logical point.
* Workflow State: an object carrying the data that travels between nodes.

## Setup and types

Begin with the necessary imports and the type that represents the workflow state. This `ReviewState` carries the generated content, the approval decision, and a status flag.

```python theme={null}
# imports
from typing import TypedDict
from dataclasses import dataclass
import copy
```

Define the workflow state type:

```python theme={null}
class ReviewState(TypedDict):
    content: str
    approval: str
    status: str
```

Next, define a simple `InterruptRequest` dataclass to represent a pause/interrupt. In a real runtime, invoking an interrupt would hand control back to the host with a payload describing what needs review.

```python theme={null}
@dataclass
class InterruptRequest:
    payload: dict

    @staticmethod
    def interrupt(payload: dict) -> "InterruptRequest":
        """Create an interrupt request with the given payload."""
        return InterruptRequest(payload=payload)
```

## Workflow nodes: generate, interrupt, resume

Below are the three main nodes in this simulated workflow: content generation, issuing an interrupt, and resuming based on a decision.

```python theme={null}
def generate_content(state: ReviewState) -> ReviewState:
    state = copy.deepcopy(state)
    state["content"] = "Draft: This is the generated content that requires review."
    state["status"] = "needs_review"
    return state


def request_review(state: ReviewState) -> InterruptRequest:
    """Simulate a node issuing an interrupt for human review."""
    payload = {
        "content": state["content"],
        "reason": "Please approve or request changes."
    }
    return InterruptRequest.interrupt(payload=payload)


def resume_workflow(state: ReviewState, approval: str) -> ReviewState:
    """Continue workflow based on the approval decision."""
    state = copy.deepcopy(state)
    state["approval"] = approval
    if approval.lower() in ("approved", "approve", "yes"):
        state["status"] = "approved"
    else:
        state["status"] = "changes_requested"
    return state
```

## State and function summary

Use the following table to quickly understand the state fields and the purpose of each function in this demo.

| Item                               | Description                                                | Example / Notes                                                    |
| ---------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------ |
| `ReviewState` fields               | State passed between workflow nodes                        | `{"content": "", "approval": "", "status": "started"}`             |
| `content`                          | The generated draft or artifact requiring review           | `"Draft: This is the generated content that requires review."`     |
| `approval`                         | Decision returned by the reviewer                          | `"approved"` or `"changes_requested"`                              |
| `status`                           | Current lifecycle status of the state                      | `"started"`, `"needs_review"`, `"approved"`, `"changes_requested"` |
| `generate_content(state)`          | Produces initial content and sets status to `needs_review` | Returns updated `ReviewState`                                      |
| `request_review(state)`            | Emits an `InterruptRequest` with review payload            | Simulates a runtime interrupt                                      |
| `resume_workflow(state, approval)` | Reconciles the decision and updates status                 | Returns updated `ReviewState`                                      |

## Example run (end-to-end)

This block shows the full flow: initialize state, generate content, request review (interrupt), then resume after a simulated reviewer decision.

```python theme={null}
# initial state
state: ReviewState = {
    "content": "",
    "approval": "",
    "status": "started"
}

# Step 1: generate content
state = generate_content(state)
print("After generation:", state)
# Step 2: interrupt for review
interrupt = request_review(state)
print("Interrupt payload:", interrupt.payload)
# (External human reviews the payload and returns a decision.)
# Simulate a reviewer decision:
decision = "approved"  # or "changes_requested"

# Step 3: resume workflow with the decision
state = resume_workflow(state, decision)
print("After resume:", state)
# After resume: {'content': 'Draft: This is the generated content that requires review.', 'approval': 'approved', 'status': 'approved'}
```

## How this maps to workflow runtimes

* The `InterruptRequest` models the runtime interrupt object you would encounter when a node pauses for external input in a workflow system.
* The `payload` contains only the minimal necessary data for a human reviewer; in production this can be extended with metadata, links to artifacts, or audit IDs.
* When the external decision returns, the workflow runtime or controller reconciles state and resumes processing from the same logical point, preserving idempotency and traceability.
* This pattern enables manual checks, approvals, gated deployments, or other human approvals within otherwise automated processes.

<Callout icon="lightbulb" color="#1CB2FE">
  In production systems, interrupts are typically implemented as runtime primitives that persist state, emit events/notifications, and secure the review channel. Use this pattern to model human review gates while keeping your core workflow logic deterministic and resumable.
</Callout>

## Links and references

* [Kubernetes Documentation](https://kubernetes.io/docs/)
* [Workflow Patterns and Best Practices](https://martinfowler.com/articles/workflow-patterns.html)
* [Designing Human-in-the-Loop Systems — Research and Guidelines](https://www.microsoft.com/en-us/research/publication/human-in-the-loop/)

This pattern is a practical approach to integrating manual approvals into automated workflows while maintaining clarity, auditability, and the ability to resume execution from a known state.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/langgraph/module/0512078c-4290-4d71-9531-0b12f54f10c6/lesson/aca8613b-e199-4adc-8d6e-668daecdd6be" />

  <Card title="Practice Lab" icon="flask-conical" cta="Learn more" href="https://learn.kodekloud.com/user/courses/langgraph/module/0512078c-4290-4d71-9531-0b12f54f10c6/lesson/5c16785f-b42f-4856-bd6c-ef1845fa1881" />
</CardGroup>
