LangChain

Add a human approval checkpoint to any LangChain tool or chain step. Works with LangChain JS/TS and Python, including LangGraph.

Prerequisites

  • Python 3.9+ or Node.js environment.
  • cheqpoint SDK installed.
  • LangChain framework configured with custom tools.

Steps

  1. Initialize the Cheqpoint client with your CQ_API_KEY.
  2. Identify the sensitive tools in your LangChain toolkit (e.g., DatabaseWriteTool, StripeChargeTool).
  3. Inside the tool's _run or _arun method, call client.request() with the tool's input parameters.
  4. Block execution while waiting for the Cheqpoint response.
  5. If the response status is approved, execute the original tool logic.
  6. If the response status is rejected, raise a ValueError or return a message to the LLM stating the action was blocked by human oversight.

Installation

bash
pip install cheqpoint langchain langchain-openai

Sample request payload

json
{
  "action": "db_delete_record",
  "summary": "Agent attempting to delete record from 'customers' table",
  "details": {
    "table": "customers",
    "record_id": "881",
    "query": "DELETE FROM customers WHERE id = 881"
  },
  "justification": "User requested account deletion under GDPR right to be forgotten."
}

Sample Cheqpoint response

json
{
  "status": "approved",
  "modifiedDetails": {
    "query": "UPDATE customers SET deleted_at = NOW() WHERE id = 881"
  },
  "decisionNote": "Perform soft delete instead of hard delete for audit safety."
}

Python — request_sync() in a LangChain tool

python
from cheqpoint import CheqpointClient

cheq = CheqpointClient(api_key="cq_live_...")

class DatabaseWriteTool(BaseTool):
    name = "database_write"
    description = "Execute a write query after human approval"

    def _run(self, query: str, table: str, record_id: str) -> str:
        result = cheq.request_sync(
            action="db_delete_record",
            summary=f"Agent attempting to delete record from '{table}' table",
            details={"table": table, "record_id": record_id, "query": query},
            justification="User requested account deletion under GDPR.",
            timeout_ms=30_000,  # poll up to 30 s
        )
        if result["status"] == "approved":
            effective = result.get("modifiedDetails") or {"query": query}
            return execute_query(effective["query"])
        return f"Action blocked: {result.get('decisionNote', 'rejected by reviewer')}"

Notes

You have full control over what data is passed into the details object to provide human reviewers with sufficient context.

Tips

Start by routing only high-risk or high-value actions to minimize friction while maintaining oversight.

Get your Connection Key at cheqpoint.co/signup.