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
Metadata
Release files for langchain-noxy 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langchain_noxy-1.0.2.tar.gz | 16.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langchain_noxy-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.0 kB
Release files / langchain_noxy-1.0.2.tar.gz
| Download URL | langchain_noxy-1.0.2.tar.gz |
|---|---|
| Size | 16.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a8487b92f86d2163ba2b68c96142432fe94591f50d5cd17c525f52eaf9901182
|
|
BLAKE2b-256 checksum How to use checksums |
6cc6f6ca3b2137305893521f52e8e1ea3275722f6ae76a2aacc4ce46fc53b1fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / langchain_noxy-1.0.2-py3-none-any.whl
| Download URL | langchain_noxy-1.0.2-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8eacada7aa69523ac507d28b810f49e2a0c83b0ae8331dcd57bcc09c58d08ddc
|
|
BLAKE2b-256 checksum How to use checksums |
d4eadc0755a80a8f70f7b1a4aa0998f14fe89551fe1320506ca62635020357aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|