Skip to main content

pushary-langgraph

Human-in-the-loop for LangGraph and LangChain. Ask a real human to approve, and get the answer on their phone. Two seams:

  • A blocking ask_human you call from inside a node.
  • A durable pushary_interrupt that parks the graph with LangGraph's native interrupt() and resumes on a signed webhook, so a long wait holds no compute and survives a restart.

Requires the Pushary Partner plan.

Install

pip install pushary-langgraph

Set PUSHARY_API_KEY (get it in your dashboard).

Connect a phone once

from pushary_langgraph import connect

link = connect("user_123")  # show this to your end-user; one tap connects their phone

Ask a human inside a node

from pushary_langgraph import ask_human

def approval_node(state):
    d = ask_human("Approve this transfer?", external_id=state["user_id"], node="approval")
    return {"approved": d["approved"]}

ask_human blocks, polls durably, and fails closed. The idempotency key is derived from external_id + node + question, so a node that re-runs on resume hits the same decision instead of paging the human twice.

Durable interrupt

from pushary_langgraph import pushary_interrupt

def approval_node(state):
    answer = pushary_interrupt(
        "Approve this transfer?",
        external_id=state["user_id"],
        node="approval",
        callback_url=os.environ["PUSHARY_CALLBACK_URL"],  # omit to block instead of park
    )
    return {"approved": answer == "yes"}

With a callback_url, the node opens the decision and calls LangGraph's interrupt() to park the graph (a checkpointer is required). Keep any code before the call idempotent, the whole node re-runs on resume.

Resume from the webhook

from pushary_langgraph import resolve_pushary_callback, SIGNATURE_HEADER
from langgraph.types import Command

# POST /pushary/callback
def callback(request):
    raw = request.body
    cb = resolve_pushary_callback(raw, request.headers.get(SIGNATURE_HEADER), os.environ["PUSHARY_WEBHOOK_SECRET"])
    if not cb:
        return ("bad signature", 401)
    thread_id = lookup_thread(cb["correlationId"])  # your own correlationId -> thread_id map
    graph.invoke(Command(resume=cb["answer"]), {"configurable": {"thread_id": thread_id}})
    return ("ok", 200)

API

  • connect(external_id, *, api_key=None, base_url=None) — enroll an end-user's phone, returns the link.
  • ask_human(question, *, external_id, type="confirm", options=None, node=..., ...) — blocking, returns the decision dict.
  • pushary_interrupt(question, *, external_id, node=..., callback_url=None, ...) — blocking, or durable when callback_url is set.
  • resolve_pushary_callback(raw_body, signature, secret) — verify + parse a callback into {correlationId, answer, approved, ...}.
  • describe_answer(type, result), is_affirmative(answer), deterministic_key(parts), SIGNATURE_HEADER.

License

MIT

Release files for pushary-langgraph 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pushary-langgraph 0.2.0
File Size Uploaded
pushary_langgraph-0.2.0.tar.gz 7.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pushary-langgraph 0.2.0
File Interpreter ABI Platform
pushary_langgraph-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 13.2 kB

Release files / pushary_langgraph-0.2.0.tar.gz

Download URL pushary_langgraph-0.2.0.tar.gz
Size 7.8 kB
Tags Source
SHA-256 checksum
How to use checksums
4ab74876cd520eed4f929189df73dfe7a8d4c2b886a27e8f6a9ec7144adec29b
BLAKE2b-256 checksum
How to use checksums
12edc270583c658f0daaf0afcaacfe3e5d0b0ef18fbb269791aa741426f8e1c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.

Transparency log

Release files / pushary_langgraph-0.2.0-py3-none-any.whl

Download URL pushary_langgraph-0.2.0-py3-none-any.whl
Size 5.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
17075d5c6130fa8ac2e85bfc93db8117ff9c5131e0c2e515403388fbab07545c
BLAKE2b-256 checksum
How to use checksums
9f1c8baa373e60da790b601bb3f2c6a11fc7cd54d831beaa0be6a87dfefb452f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.0

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page