Python SDK for Gatewerk — human oversight for AI agents
Project description
gatewerk
Python SDK for Gatewerk — the open-source human oversight station for AI agents.
Install
pip install gatewerk
Quick Start
from gatewerk import create_client
gw = create_client(
api_key="gw_key_...",
url="https://api.gatewerk.com",
)
# Submit a review request
review = gw.reviews.create(
"email-review",
payload={"to": "ceo@acme.com", "subject": "Q4 Report", "body": draft},
callback_url="https://my-agent.com/webhook",
priority="high",
)
print(review.id) # gw_rev_...
print(review.status) # pending
Async Support
from gatewerk import create_async_client
async with create_async_client(api_key="gw_key_...") as gw:
review = await gw.reviews.create("email-review", payload={...})
feedback = await gw.feedback.query(template="email-review")
Framework integrations
| Framework | Install | Status |
|---|---|---|
| LangGraph | pip install gatewerk[langgraph] |
available |
| CrewAI | pip install gatewerk[crewai] |
available |
LangGraph in 30 seconds:
from gatewerk import create_client
from gatewerk.integrations.langgraph import gatewerk_interrupt
gw = create_client(api_key="gw_key_...")
def gated_node(state):
decision = gatewerk_interrupt(gw, template="refund_approval", payload={...})
return {"approved": decision.approved}
See gatewerk/integrations/langgraph/README.md for the full guide, including the polling alternative (await_decision), async variants, and the LangGraph re-execution caveat.
CrewAI in 30 seconds:
from crewai import Agent, Task, Crew
from gatewerk import create_client
from gatewerk.integrations.crewai import GatewerkApprovalTool
gw = create_client(api_key="gw_key_...")
approval_tool = GatewerkApprovalTool(gw, template="refund_approval")
agent = Agent(role="Customer Support", goal="...", tools=[approval_tool])
Crew(agents=[agent], tasks=[Task(description="...", agent=agent, expected_output="...")]).kickoff()
The tool pauses the agent, routes the request to the Gatewerk dashboard, and returns "APPROVED", "REJECTED", or "CHANGES_REQUESTED: ..." once a human decides. See gatewerk/integrations/crewai/README.md for the full guide.
Resources
| Resource | Methods |
|---|---|
gw.reviews |
create() get() list() decide() retry() update() cancel_request() versions() create_token() list_auto_paginate() |
gw.chains |
create() get() get_for_review() |
gw.notes |
create() get() list() list_auto_paginate() update() delete() pin() unpin() tags() |
gw.templates |
list() get() create() update() delete() stats() |
gw.feedback |
query() |
gw.audit |
query() |
gw.stats |
get() |
gw.webhooks |
verify() deliveries() |
gw.key_info() |
Introspect API key scopes |
Typed Responses
All methods return Pydantic models:
from gatewerk import Review, ReviewList, Template, FeedbackList
review = gw.reviews.get("gw_rev_...")
review.id # str
review.status # str
review.payload # dict[str, Any]
review.current_version # int
review.auto_approved # bool | None
Auto-Pagination
# Iterate all reviews without managing offsets
for review in gw.reviews.list_auto_paginate(status="pending"):
print(review.id)
# Async
async for review in gw.reviews.list_auto_paginate(status="pending"):
print(review.id)
Retry & Resilience
The SDK automatically retries on transient errors (429, 500, 502, 503, 504) with exponential backoff and jitter. Rate limit Retry-After headers are respected.
# Customize retry behavior
gw = create_client(
api_key="gw_key_...",
max_retries=5, # default: 2, set 0 to disable
timeout=60.0, # default: 30s
)
Error Handling
from gatewerk import (
GatewerkError, # Base — all errors
InvalidRequestError, # 400
AuthenticationError, # 401
ForbiddenError, # 403
NotFoundError, # 404
ConflictError, # 409
RateLimitError, # 429 (includes .retry_after)
)
try:
review = gw.reviews.get("gw_rev_nonexistent")
except NotFoundError as e:
print(e.message) # "Review not found"
print(e.status_code) # 404
print(e.code) # "review_not_found"
except RateLimitError as e:
print(e.retry_after) # seconds until retry
Webhook Verification
Every delivery carries two signature headers. Verify either depending on whether you need replay protection.
v1 (authenticity only, no replay protection)
The SDK's gw.webhooks.verify() helper accepts the v1 X-Webhook-Signature header:
# In your Flask/FastAPI webhook handler
payload = gw.webhooks.verify(
raw_body=request.body,
signature_header=request.headers["X-Webhook-Signature"],
secret="whsec_...",
)
# payload is a trusted dict: {"event": "review.decided", ...}
v2 (replay-safe; recommended for new integrations)
The X-Webhook-Signature-V2 header carries t=<unix-seconds>,v1=<hex> where hex = HMAC(f"{t}.{body}", secret). Parse, enforce freshness, then constant-time compare. No SDK helper yet — follow the manual pattern:
import hmac
import hashlib
import time
def verify_v2(raw_body: bytes, header: str, secret: str, tolerance_seconds: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
ts = int(parts["t"])
received_hex = parts["v1"]
# Freshness: reject replays outside the tolerance window.
if abs(time.time() - ts) > tolerance_seconds:
return False
expected_hex = hmac.new(
secret.encode(),
f"{ts}.{raw_body.decode()}".encode(),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected_hex, received_hex)
assert verify_v2(
request.body,
request.headers["X-Webhook-Signature-V2"],
"whsec_...",
)
Receivers should also dedup on X-Webhook-Id (stable across retries) to survive the legitimate retry flow. A v2-verified payload MAY still be a legitimate retry; the header id is the idempotency key.
Logging
The SDK logs via Python's standard logging module under the gatewerk logger:
import logging
logging.getLogger("gatewerk").setLevel(logging.DEBUG)
Environment Variables
| Variable | Description |
|---|---|
GATEWERK_API_KEY |
API key (fallback if not passed to create_client) |
GATEWERK_URL |
API URL (default: http://localhost:3100) |
License
Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gatewerk-0.1.1.tar.gz.
File metadata
- Download URL: gatewerk-0.1.1.tar.gz
- Upload date:
- Size: 47.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0dca12c7bddceb390298891980ee9d34c69a699cc1fea5ed3fe982963486b18f
|
|
| MD5 |
40c4da0e12e53fcbc1669a34dfd6f478
|
|
| BLAKE2b-256 |
5823ec0617c4bbe84260845e7c39e80361c1cddd414f3cdbb95afe19b001a1af
|
Provenance
The following attestation bundles were made for gatewerk-0.1.1.tar.gz:
Publisher:
publish-sdk-py.yml on gatewerk/gatewerk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gatewerk-0.1.1.tar.gz -
Subject digest:
0dca12c7bddceb390298891980ee9d34c69a699cc1fea5ed3fe982963486b18f - Sigstore transparency entry: 1569816350
- Sigstore integration time:
-
Permalink:
gatewerk/gatewerk@83a37bef20be09b52cf690465e3a90fa10a77708 -
Branch / Tag:
refs/tags/sdk-py-v0.1.1 - Owner: https://github.com/gatewerk
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk-py.yml@83a37bef20be09b52cf690465e3a90fa10a77708 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gatewerk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: gatewerk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 62.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
262de9bb3a0c6a0e985fa133c4bf0bc9e6186fc9e9a07abe7317c331dc2e2c50
|
|
| MD5 |
e60a3be7bfc33b7f96da10047430ae04
|
|
| BLAKE2b-256 |
be45b7213ec54808d1aff2ef03dc9c8944441f12644f02b6f1e63f5b394f78ab
|
Provenance
The following attestation bundles were made for gatewerk-0.1.1-py3-none-any.whl:
Publisher:
publish-sdk-py.yml on gatewerk/gatewerk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gatewerk-0.1.1-py3-none-any.whl -
Subject digest:
262de9bb3a0c6a0e985fa133c4bf0bc9e6186fc9e9a07abe7317c331dc2e2c50 - Sigstore transparency entry: 1569816398
- Sigstore integration time:
-
Permalink:
gatewerk/gatewerk@83a37bef20be09b52cf690465e3a90fa10a77708 -
Branch / Tag:
refs/tags/sdk-py-v0.1.1 - Owner: https://github.com/gatewerk
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk-py.yml@83a37bef20be09b52cf690465e3a90fa10a77708 -
Trigger Event:
push
-
Statement type: