decionis-langchain wraps a LangChain (Python) tool so each call asks Decionis first, with the call's own arguments, and the tool runs only on a verdict that allows it. The agent sees the same tool: its name, description and argument schema do not change.
It depends on the decionis SDK (0.2.0, MIT), which pip installs with it. The client needs an organization API key and its tenant id.
pip install decionis-langchain
pip install 'decionis-langchain[langgraph]'from decionis import DecionisClient
from decionis_langchain import DecionisGateTool
from langchain_core.tools import tool
@tool
def send_refund(customer_id: str, amount_usd: int) -> str:
"""Issue a refund. Idempotent on customer_id + amount + day."""
...
client = DecionisClient(api_key="…", base_url="https://api.decionis.com")
gated_refund = DecionisGateTool.wrap(
inner_tool=send_refund,
client=client,
tenant_id="org-uuid",
workflow_key="refund_execution",
site_base_url="https://decionis.com",
)
agent.bind_tools([gated_refund])DecionisGateTool wraps any LangChain BaseTool: _run and _arun ask Decionis first and invoke the inner tool only when it is permitted, with the inner tool's name, description and argument schema unchanged. decionis_gate_node puts the same check in a LangGraph node, which routes to allowed or blocked.
ALLOW runs the tool. BLOCK, REVIEW_REQUIRED, ESCALATE and ERROR raise DecionisGateRefusal before it runs, carrying the Decision Dossier id and, when there is one, its verify link.
With shadow_mode=True the decision is still asked for and recorded, and the tool runs whatever the verdict: start here, and remove it once the verdicts match the policy you meant.
A timeout after retries, an HTTP error or no connection. In shadow, the tool runs anyway: the adapter logs a warning and passes the failure to on_decision as error, with decision=None. In enforcement, the error is raised and the tool does not run.