Skip to content

About

AEAP Composition Boundary Adapter for LangChain (Python). Thin wrapper that attaches the AEAP Runtime Decision Point to LangChain tool invocations. Published as aiyoplane-langchain on PyPI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

aiyoplane-langchain

AEAP Composition Boundary Adapter for LangChain.

A thin wrapper that attaches the AEAP Runtime Decision Point (RDP) to LangChain's tool-invocation surface. Consequential tool executions produce independently verifiable Execution Receipts. The adapter does not alter LangChain's agent, memory, prompt, or retrieval surfaces — only the specific boundary where a tool is about to execute.

pip install aiyoplane-langchain

What this adapter is (and is not)

It is: the shape AEAP takes when attached to a LangChain BaseTool. The underlying authorization logic lives in aiyoplane-mcp-authz; this package distributes that logic into the LangChain ecosystem under LangChain-native idioms.

It is not: a new authorization product. It is not a LangChain plugin that adds features. It is not a LangSmith / LangFuse replacement. It has no feature backlog of its own — if the behavior needs changing, the change belongs in aiyoplane-mcp-authz so every AEAP adapter inherits it.

See the AEAP specification §9 for the Composition Boundary primitive this adapter realizes.

Install

pip install aiyoplane-langchain
# Peer dependencies installed automatically:
#   aiyoplane-mcp-authz >= 1.0.1
#   langchain-core >= 0.3, < 0.4

Minimal usage

from langchain_core.tools import tool
from aiyoplane_mcp_authz import create_aiyo_mcp_authz, create_local_rdp
from aiyoplane_langchain import wrap_tool

# 1. Define a LangChain tool as you normally would.
@tool
def transfer_funds(amount: int, to_account: str) -> str:
    """Transfer funds between accounts."""
    return _actually_transfer(amount, to_account)

# 2. Define the AEAP policy (local RDP for development; HostedRdp for production).
policy = {
    "rules": [
        {"action_type": "payment", "amount_max": 1_000, "effect": "allow"},
        {"action_type": "payment", "amount_max": 10_000, "effect": "escalate"},
        {"action_type": "payment", "effect": "block"},
    ]
}

authz = create_aiyo_mcp_authz(
    rdp=create_local_rdp(policy=policy),
    tool_config={
        "transfer_funds": {
            "aiyo_gated": True,
            "action": {"type": "payment"},
        },
    },
)

# 3. Wrap the tool at its Composition Boundary.
guarded_transfer = wrap_tool(
    transfer_funds,
    authz=authz,
    intent_builder=lambda args: {
        "type": "payment",
        "amount": args["amount"],
        "target": args["to_account"],
    },
)

# 4. Use the wrapped tool anywhere LangChain accepts a tool.
#    On ALLOW:    the inner tool runs normally.
#    On ESCALATE: aiyoplane_langchain.EscalationRequired is raised.
#    On BLOCK:    aiyoplane_langchain.BlockedByPolicy is raised; the tool never executes.

Wrapping a whole tool list

The common case is "here are my agent's tools; some of them need AEAP gating."

from aiyoplane_langchain import wrap_tools

all_tools = [search_docs, read_user, transfer_funds, delete_account]

guarded_tools = wrap_tools(
    all_tools,
    authz=authz,
    intent_builders={
        "transfer_funds": lambda args: {"type": "payment", "amount": args["amount"]},
        "delete_account": lambda args: {"type": "destructive", "target": args["user_id"]},
        # search_docs and read_user are omitted — they pass through un-wrapped.
    },
)

Tools whose name is not a key in intent_builders pass through unchanged. This is intentional: AEAP gating is an explicit opt-in, not a wholesale wrapper. The Protected Party's policy decides which actions are consequential.

Composition Boundary — what the adapter actually does

The adapter is a wrapper around LangChain's BaseTool._run / _arun. On invocation:

  1. Intent construction. The adapter calls the user-supplied intent_builder(tool_args) to produce an AEAP Intent payload. See AEAP §3.
  2. RDP evaluation. The Intent is passed to the AiyoAuthz middleware from aiyoplane-mcp-authz, which calls the RDP (local or hosted).
  3. Verdict composition.
    • ALLOW → the inner tool's _run / _arun executes with the original arguments. The verified Execution Receipt is available for inspection and optionally returned alongside the result (see return_receipt=True).
    • ESCALATE → EscalationRequired is raised. The exception carries an escalation_id for correlation. The LangChain agent / chain decides how to route the escalation.
    • BLOCK → BlockedByPolicy is raised. The inner tool never executes.
  4. Fail-closed default. Any ambiguous condition — missing intent_builder, non-dict Intent, RDP unreachable, RDP exception, misconfigured tool_config — results in BlockedByPolicy. See AEAP §2.2 invariant 5.

Local vs. hosted RDP

The adapter is RDP-agnostic — it delegates evaluation to the AiyoAuthz middleware, which accepts either a LocalRdp (in-process, for development and self-hosted deployments) or a HostedRdp (connects to api.aiyoplane.com, for managed deployments). Switching is a one-line change in the AiyoAuthz construction; the adapter and the LangChain tool are unchanged.

# Development / self-hosted:
from aiyoplane_mcp_authz import create_local_rdp
authz = create_aiyo_mcp_authz(rdp=create_local_rdp(policy=policy), tool_config={...})

# Production / hosted:
from aiyoplane_mcp_authz import create_hosted_rdp
authz = create_aiyo_mcp_authz(
    rdp=create_hosted_rdp(api_key="aiyo_live_..."),
    tool_config={...},
)

API reference

wrap_tool(tool, *, authz, intent_builder, tool_name_for_authz=None, return_receipt=False)

Wrap a single BaseTool. Returns an AiyoLangChainTool.

  • tool — the original LangChain tool
  • authz — an AiyoAuthz instance
  • intent_builder — a callable (tool_args: dict) -> dict
  • tool_name_for_authz — override for the authz.tool_config key; defaults to tool.name
  • return_receipt — if True, the wrapped tool returns {"result": ..., "aeap_receipt": ...} on ALLOW

wrap_tools(tools, *, authz, intent_builders, return_receipt=False)

Wrap a collection in one call. Tools whose name is not a key in intent_builders pass through unchanged.

AiyoLangChainTool

The BaseTool subclass produced by wrap_tool. You rarely need to construct this directly.

Exceptions

  • AiyoLangChainError — base class
  • AdapterConfigError — adapter configuration is invalid (missing tool_config entry, bad intent_builder)
  • BlockedByPolicy — RDP returned BLOCK; the tool did not execute
  • EscalationRequired — RDP returned ESCALATE; the tool call is held pending resolution

License

Apache License 2.0. See LICENSE for the full text.

Links

LangChain is a trademark of LangChain, Inc. This package is an independent AEAP Composition Boundary Adapter and is not affiliated with or endorsed by LangChain, Inc.

Verify First. Execute Second.

About

AEAP Composition Boundary Adapter for LangChain (Python). Thin wrapper that attaches the AEAP Runtime Decision Point to LangChain tool invocations. Published as aiyoplane-langchain on PyPI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages