-
Notifications
You must be signed in to change notification settings - Fork 0
The LangChain middleware page, now that ctrlrun-langchain is on PyPI #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| --- | ||
| title: "Use the LangChain middleware" | ||
| description: "Gate every LangChain tool call with ctrlrun-langchain, through wrap_tool_call, so a refused call never runs and every decision leaves a receipt." | ||
| --- | ||
|
|
||
| This guide provides a quick overview for getting started with the CTRLRun [middleware](https://docs.langchain.com/oss/langchain/middleware/overview). CTRLRun checks every tool call your agent makes against a policy you write, before the call runs, and records what happened after. | ||
|
|
||
| ## Overview | ||
|
|
||
| ### Details | ||
|
|
||
| | Class | Package | Serializable | Downloads | Version | | ||
| | :--- | :--- | :---: | :---: | :---: | | ||
| | `CTRLRunMiddleware` | [`ctrlrun-langchain`](https://pypi.org/project/ctrlrun-langchain/) | beta/❌ |  |  | | ||
|
|
||
| ### Features | ||
|
|
||
| - **Policy-gated tool calls** — a refused call never reaches the tool, and the model is told which rule refused it | ||
| - **Once stays once** — an effect key executes at most once, across processes sharing a store | ||
| - **Unknown outcomes stay unknown** — a tool that raises leaves the effect unresolved rather than retried | ||
| - **Human approval** — a policy decision of `approve` holds the call for a person | ||
| - **A receipt for every decision** — requests, decisions and results, refusals included | ||
|
|
||
| --- | ||
|
|
||
| ## Setup | ||
|
|
||
| No account and no API key. CTRLRun is a library, and the policy is a file in your repository. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '1,115p' docs/guides/langchain-middleware.mdx
rg -n --glob '!*lock*' 'ctrlrun-langchain|langchain-openai|langchain\[openai\]|init_chat_model|ChatOpenAI' pyproject.toml setup.cfg setup.py packages . 2>/dev/null | head -180Repository: CTRLRun/ctrlrun-docs Length of output: 620 🌐 Web query:
💡 Result: <search_synthesis> <source_evidence> Citations:
🏁 Script executed: #!/bin/bash
set -u
printf '%s\n' '--- tracked files ---'
git ls-files | rg '(^|/)(pyproject\.toml|setup\.cfg|setup\.py|.*langchain.*|.*middleware.*)$' | head -120
printf '%s\n' '--- guide ---'
sed -n '1,115p' docs/guides/langchain-middleware.mdx
printf '%s\n' '--- package metadata references ---'
rg -n --glob '!*lock*' 'ctrlrun-langchain|langchain-openai|langchain\[openai\]|init_chat_model|ChatOpenAI' . | head -220Repository: CTRLRun/ctrlrun-docs Length of output: 620 🌐 Web query:
💡 Result: <search_synthesis> <source_evidence> Citations:
🌐 Web query:
💡 Result: <search_synthesis> <source_evidence> Citations:
Install the OpenAI LangChain integration and configure its credential. The guide selects Proposed fix-No account and no API key. CTRLRun is a library, and the policy is a file in your repository.
+CTRLRun itself needs no account or API key. This example uses OpenAI through LangChain, so install its integration and configure `OPENAI_API_KEY`.
-pip install ctrlrun-langchain
+pip install ctrlrun-langchain langchain-openai🤖 Prompt for AI Agents |
||
|
|
||
| ### Installation | ||
|
|
||
| ```bash | ||
| pip install ctrlrun-langchain | ||
| ``` | ||
|
|
||
| ### Write a policy | ||
|
|
||
| `ctrlrun.yaml` says how much autonomy each tool gets. Unknown tools are denied; there is no default-allow. | ||
|
|
||
| ```yaml | ||
| schema: ctrlrun.policy/v2 | ||
| actions: | ||
| lookup_order: | ||
| decision: allow | ||
| issue_refund: | ||
| effect: "refund:{payment_id}" | ||
| rules: | ||
| - when: { amount_gte: 0, amount_lte: 5000 } # up to €50.00, autonomous | ||
| decision: allow | ||
| - when: { amount_gte: 0, amount_lte: 500000 } # up to €5,000.00, ask a human | ||
| decision: approve | ||
| - decision: deny | ||
| ``` | ||
|
|
||
| ## Instantiation | ||
|
|
||
| ```python | ||
| from langchain.agents import create_agent | ||
| from ctrlrun import Control | ||
| from ctrlrun_langchain import CTRLRunMiddleware | ||
|
|
||
| control = Control.from_file("ctrlrun.yaml") | ||
|
|
||
| agent = create_agent( | ||
| model="gpt-5.5", | ||
| tools=[lookup_order, issue_refund], | ||
| middleware=[CTRLRunMiddleware(control)], | ||
| ) | ||
| ``` | ||
|
|
||
| ## Invocation | ||
|
|
||
| ```python | ||
| import ctrlrun | ||
|
|
||
| with ctrlrun.context(agent="support-agent"): | ||
| result = agent.invoke({"messages": [{"role": "user", "content": "refund order 4471"}]}) | ||
| ``` | ||
|
|
||
| Every protected call needs a principal: who is acting is an authorization input, so a call without one is denied before the policy is consulted. `ctrlrun.context(...)` supplies it in development; in production an identity provider verifies a credential instead. | ||
|
|
||
| ## What the agent sees | ||
|
|
||
| The middleware uses [`wrap_tool_call`](https://docs.langchain.com/oss/langchain/middleware/custom), so a refused call is short-circuited — the tool is never invoked, and the model receives a `ToolMessage` explaining why: | ||
|
|
||
| ```text | ||
| issue_refund amount=900000 CTRLRun refused this call: rule[2]. The tool did not run. | ||
| rm_rf CTRLRun refused this call: unknown_action. The tool did not run. | ||
| issue_refund amount=1000 (the tool runs) | ||
| issue_refund amount=1000 CTRLRun refused this call: this effect is already committed | ||
| ``` | ||
|
|
||
| That last line is the property worth knowing about. Because `handler` is the executor, the effect is reserved before the tool runs and committed from what it returned. Two agents sharing a store cannot both execute the same effect key, and a tool that raises leaves the outcome `AMBIGUOUS` rather than `FAILED` — so the retry is refused until a person resolves it, instead of becoming a double charge. | ||
|
|
||
| ## Approvals | ||
|
|
||
| Where the policy says `approve`, the call is held and the model is told how to release it: | ||
|
|
||
| ```text | ||
| CTRLRun is holding this call for a human. Approve it with 'ctrlrun approve apr_...', | ||
| then ask again. The tool did not run. | ||
| ``` | ||
|
|
||
| To have the human answered *inside* the run instead, use [`ctrlrun-langgraph`](https://pypi.org/project/ctrlrun-langgraph/), which routes the approval through LangGraph's `interrupt()` and re-presents the same proposal on resume. | ||
|
|
||
| ## Next | ||
|
|
||
| - [Use the LangGraph adapter](/docs/guides/langgraph-adapter): approvals answered inside the run, through `interrupt()`. | ||
| - [Adapters](/docs/adapters): the three ways in, and why this one is prevention. | ||
| - [The middleware's README](https://github.com/CTRLRun/ctrlrun/blob/main/adapters/langchain/README.md) · [Get started](/docs/get-started/quickstart) · [Why](/docs/why). | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Repair both LangChain middleware links.
Both URLs omit
/pythonand return 404. Use the Python documentation URLs. ()docs/guides/langchain-middleware.mdx#L6-L6: Change the overview URL tohttps://docs.langchain.com/oss/python/langchain/middleware/overview.docs/guides/langchain-middleware.mdx#L84-L84: Change the custom-middleware URL tohttps://docs.langchain.com/oss/python/langchain/middleware/custom.📍 Affects 1 file
docs/guides/langchain-middleware.mdx#L6-L6(this comment)docs/guides/langchain-middleware.mdx#L84-L84🤖 Prompt for AI Agents