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.1.1

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.1.1
File Size Uploaded
pushary_langgraph-0.1.1.tar.gz 8.0 kB Details

Built distribution (wheel)

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

Total release size: 14.1 kB

Release files / pushary_langgraph-0.1.1.tar.gz

Download URL pushary_langgraph-0.1.1.tar.gz
Size 8.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e3d17db328e7e3b6e360fd8a8a85b17e0ce520bfb93f1701a1dc952d1cd3d977
BLAKE2b-256 checksum
How to use checksums
42f6de2d6c282ee491d729428b3210da9f3c920837f46090a8d4f7398b9c651e
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 2, 2026.

Transparency log

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

Download URL pushary_langgraph-0.1.1-py3-none-any.whl
Size 6.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
75cbb7a02e982366513f7d019b9eb9c6374a6d3061116224d3e4d74dc3675c01
BLAKE2b-256 checksum
How to use checksums
dc61754f6b2300cab4632e073f7ad8958624d7ab2ea9f12a67b2fdee78e7c1bf
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 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.1 This release

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