Skip to content

Interruptible Human Review

interruptible-approval persists API execution state while a review is pending. It is a deterministic production-pattern example: a refund rejection ends the workflow, while approval leads to simulated refund execution and an automatic customer notification. A custom response records reviewer feedback without executing either action. The interrupt crosses /v1/responses as a standard tool call, so clients can collect the human response without understanding the graph topology.

Before pausing, announce_review streams a short notice through a deterministic fake chat model, as an agent explaining its next step would. Streaming clients show that text above the review; non-streaming Responses carry only the review call. The notice has its own node because LangGraph reruns the interrupted node from the start on resume, which would stream it again.

The checkpointer stores pending graph state. It does not store ordinary chat history or the application document used by persistent-plot-agent. Operation identity, interrupt continuation, and retention rules are defined in OpenAI Compatibility.

LangGraph Topology

The generated native graph view keeps human review before every simulated external effect.

graph TD;
  start["__start__"] --> announce_review;
  announce_review --> review_refund;
  execute_refund --> notify_customer;
  review_refund -.-> finish["__end__"];
  review_refund -.-> execute_refund;
  notify_customer --> finish;

Request Flow

sequenceDiagram
  actor User
  participant UI as Chainlit / Open WebUI
  box LGOS API process
    participant API as /v1/responses
    participant Graph as interruptible-approval graph
  end
  participant DB as PostgreSQL checkpointer

  User->>UI: Request protected action
  UI->>API: Initial Responses request
  API->>Graph: Invoke under run coordinator
  Graph-->>API: Review notice tokens
  API-->>UI: Streamed answer text
  Graph->>DB: Save refund pause
  Graph-->>API: Refund review function call
  API-->>UI: Standard Response function_call item
  User-->>UI: Approve, reject, or enter feedback
  UI->>API: previous_response_id + output batch
  API->>Graph: Resume from checkpoint
  alt Refund rejected or feedback supplied
    Graph->>Graph: Skip protected actions
  else Refund approved
    Graph->>Graph: Execute refund idempotently
    Graph->>Graph: Notify customer idempotently
  end
  Graph-->>API: Terminal result
  API->>DB: Delete checkpoint
  API-->>UI: Final assistant text

PostgreSQL Runtime

The graph receives its PostgreSQL checkpointer and run coordinator from the API's lifespan-managed runtime. The coordinator lease covers each initial or resume request, but ends when the graph pauses; no lease is held while the user decides. The integration test closes and recreates the runtime before resume to verify that the pause survives runtime replacement.

execute_refund and notify_customer are intentionally deterministic simulations. In a real application, replace them with durable operations that supply a stable idempotency key to each downstream system. Keep external effects in nodes after the interrupt, and make those nodes idempotent because a crash can still replay them.

The demo uses LGOS's default shared checkpoint scope, so multi-tenant applications must derive that scope from authenticated server state.

The demo API deletes runs left paused longer than LGOS_INTERRUPT_TTL_MINUTES. Production deployments must also follow LangGraph's interrupt idempotency rules.

The application must also authorize and audit the reviewing identity. Interrupt results are workflow input, not proof of authorization. Applications that must recover a lost terminal response also need their own result/idempotency store; LGOS deletes the checkpoint after terminal completion.

See Docker Compose for schema setup, connection capacity, advisory-lock requirements, and strict checkpoint deserialization.

Try It

Send Refund order ORDER-123 in Chainlit or Open WebUI. Rejecting the refund finishes without executing an action. Approving it simulates the refund and customer notification. Choosing the custom-response path records arbitrary reviewer feedback and also finishes without executing an action.