LangChain connector for Noxy human-in-the-loop — interrupt/resume with relay outcome polling via noxy-sdk.
Project description
Noxy LangChain Connector
LangChain connector for Noxy human-in-the-loop guardrails. Uses HumanInTheLoopMiddleware to pause agent tool calls, routes encrypted approval prompts to all devices registered for the identity (web, iOS, Android, Telegram), and resumes execution when you poll relay for the settled outcome via noxy-sdk (GetDecisionOutcome).
Installing langchain-noxy pulls in noxy-sdk automatically; you do not need a separate checkout of the Noxy SDK.
Flow
sequenceDiagram
participant A as LangChain Agent
participant SDK as noxy-sdk
participant N as Noxy Relay
participant D as User Devices
A->>SDK: send_decision (tool approval)
SDK->>N: RouteDecision
N->>D: Deliver to registered devices
A->>A: interrupt() — state saved to checkpointer
Note over A: Agent suspended
loop Poll GetDecisionOutcome
SDK->>N: get_decision_outcome
N-->>SDK: pending / approved / rejected / expired
end
SDK->>A: Command(resume=HITLResponse)
A->>A: Continue with approved/rejected tool calls
- The agent proposes a guarded tool call.
NoxyHumanInTheLoopMiddlewareroutes an encrypted actionable to all devices for the identity.- LangChain calls
interrupt()— the agent suspends and persists state via a checkpointer. - User responds on any registered device or the decision TTL expires on relay.
- Your process calls
wait_for_decision_outcome(SDK) orbridge.wait_and_resume(...). - The agent continues with approved or rejected tool calls.
Relay delivers outcomes via gRPC polling (GetDecisionOutcome), with exponential backoff in the SDK.
Requirements
- Python >= 3.10
- A LangChain agent created with
create_agentand a checkpointer - A Noxy app token and target identity (phone, email, user id, or wallet
0x…)
Installation
pip install langchain-noxy
Optional FastAPI example server:
pip install "langchain-noxy[examples]"
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
NOXY_APP_TOKEN |
Yes | — | App token from the Noxy dashboard |
NOXY_IDENTITY_ID |
Yes* | — | Target identity: phone, email, user id, or wallet |
NOXY_ENDPOINT |
No | https://relay.noxy.network |
Relay gRPC endpoint |
MODEL |
No | openai:gpt-4o-mini |
Chat model for the poll_resume_server example |
*Identity is passed to NoxyLangChainBridge(client, identity_id) in code; use the env var when your app reads it from the environment.
Copy .env.example to .env when running repository examples locally (never commit real tokens).
import os
from noxy import NoxyConfig, init_noxy_agent_client
client = init_noxy_agent_client(
NoxyConfig(
endpoint=os.environ.get("NOXY_ENDPOINT", "https://relay.noxy.network"),
auth_token=os.environ["NOXY_APP_TOKEN"],
decision_ttl_seconds=3600,
)
)
Quick start
import uuid
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langgraph.checkpoint.memory import InMemorySaver
from noxy import NoxyConfig, init_noxy_agent_client
from langchain_noxy import NoxyLangChainBridge
@tool
def transfer_funds(to: str, amount: str) -> str:
"""Transfer funds."""
return f"Sent {amount} to {to}"
client = init_noxy_agent_client(
NoxyConfig(
endpoint="https://relay.noxy.network",
auth_token="your-app-token",
decision_ttl_seconds=3600,
)
)
bridge = NoxyLangChainBridge(client, "user@example.com")
agent = create_agent(
init_chat_model("openai:gpt-4o-mini"),
tools=[transfer_funds],
middleware=[bridge.create_hitl_middleware({"transfer_funds": True})],
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
# agent.invoke(...) suspends when transfer_funds is proposed; read decision_id from interrupt
final = bridge.wait_and_resume(agent, "<decision_id>")
Manual polling
from noxy.decision_outcome import WaitForDecisionOutcomeOptions
resume_handler = bridge.create_resume_handler(agent)
response = client.wait_for_decision_outcome(
WaitForDecisionOutcomeOptions(decision_id="<decision_id>", identity_id="user@example.com")
)
final = resume_handler.resume_from_poll_response(
response, decision_id="<decision_id>", identity_id="user@example.com"
)
Outcome mapping
Noxy relay outcomes map to LangChain HITL decisions (via hitl_response_from_outcome):
approved→{"type": "approve"}rejected/expired/timeout→{"type": "reject", "message": "..."}
Poll tuning
Pass WaitForDecisionOutcomeOptions to bridge.wait_and_resume (same fields as noxy-sdk):
| Field | Default | Description |
|---|---|---|
initial_poll_interval_ms |
400 |
First delay between polls |
max_poll_interval_ms |
30000 |
Cap between polls |
max_wait_ms |
900000 |
Stop polling and resume with timeout outcome |
backoff_multiplier |
1.6 |
Exponential backoff factor |
API
| Symbol | Description |
|---|---|
NoxyLangChainBridge |
Wires client, registry, middleware factory, and wait_and_resume |
NoxyHumanInTheLoopMiddleware |
LangChain middleware that routes tool approvals to Noxy |
NoxyAgentResumeHandler.wait_and_resume |
SDK poll loop + Command(resume=...) |
NoxyAgentResumeHandler.resume_from_poll_response |
Resume from one terminal poll |
PendingDecisionRegistry |
Maps decision_id → thread_id for resume |
build_hitl_actionable(...) |
Build actionable payload from HITL action requests |
hitl_response_from_outcome(...) |
Map Noxy outcome to LangChain HITL resume value |
parse_webhook_payload(...) |
Optional: parse webhook-shaped JSON if you bridge events yourself |
Examples
Example scripts are maintained in the GitHub repository (they are not shipped inside the PyPI wheel). Clone the repo to run them:
git clone https://github.com/noxy-network/langchain-connector.git
cd langchain-connector
pip install ".[examples]"
cp .env.example .env # set NOXY_APP_TOKEN and NOXY_IDENTITY_ID
examples/basic.py— mock client, no relay requiredexamples/poll_resume_server.py— FastAPI:POST /runs, thenPOST /runs/wait
python examples/basic.py
export NOXY_APP_TOKEN="your-app-token"
export NOXY_IDENTITY_ID="user@example.com"
uvicorn examples.poll_resume_server:app --reload
Development
For contributors working on this repository:
git clone https://github.com/noxy-network/langchain-connector.git
cd langchain-connector
pip install ".[dev,examples]"
make test
make build
make publish-check
License
MIT
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 langchain_noxy-1.0.2.tar.gz.
File metadata
- Download URL: langchain_noxy-1.0.2.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8487b92f86d2163ba2b68c96142432fe94591f50d5cd17c525f52eaf9901182
|
|
| MD5 |
2365fd312e10f07a7d9dc14070d0494c
|
|
| BLAKE2b-256 |
6cc6f6ca3b2137305893521f52e8e1ea3275722f6ae76a2aacc4ce46fc53b1fe
|
File details
Details for the file langchain_noxy-1.0.2-py3-none-any.whl.
File metadata
- Download URL: langchain_noxy-1.0.2-py3-none-any.whl
- Upload date:
- Size: 14.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8eacada7aa69523ac507d28b810f49e2a0c83b0ae8331dcd57bcc09c58d08ddc
|
|
| MD5 |
01fe1c1801cd58a0f557394871e758da
|
|
| BLAKE2b-256 |
d4eadc0755a80a8f70f7b1a4aa0998f14fe89551fe1320506ca62635020357aa
|