Metadata-Version: 2.4
Name: langchain-edon
Version: 0.1.0
Summary: EDON governance for LangChain agents — govern, audit, and enforce every tool call
Project-URL: Homepage, https://edoncore.com
Project-URL: Documentation, https://docs.edoncore.com
Project-URL: Repository, https://github.com/EDONCORE/langchain-edon
Project-URL: Issues, https://github.com/EDONCORE/langchain-edon/issues
Author-email: EDON Core <sdk@edoncore.com>
License: MIT
Keywords: agents,ai,audit,edon,governance,langchain,safety
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Security
Requires-Python: >=3.9
Requires-Dist: edon>=0.1.0
Requires-Dist: langchain-core>=0.1.0
Description-Content-Type: text/markdown

# langchain-edon · [![PyPI](https://img.shields.io/pypi/v/langchain-edon)](https://pypi.org/project/langchain-edon) [![Python](https://img.shields.io/pypi/pyversions/langchain-edon)](https://pypi.org/project/langchain-edon) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

**Runtime governance for LangChain agents.** Evaluate and enforce every tool call before it executes — ALLOW, BLOCK, or escalate to a human.

```bash
pip install langchain-edon
```

---

## What this does

`langchain-edon` wraps your LangChain tools so every call goes through [EDON](https://edoncore.com) before execution. Your agent keeps using tools exactly as before — EDON just intercepts each call and checks it against your policy.

```
Agent decides to call a tool
         ↓
  EDON evaluates the action
         ↓
  ALLOW → tool executes normally
  BLOCK → EdonBlockedError raised
  HUMAN_REQUIRED → escalation raised
```

Every decision is logged to a tamper-evident audit trail.

---

## Quickstart (2 minutes)

### 1. Install

```bash
pip install langchain-edon langchain-openai
```

### 2. Wrap your tools

```python
import os
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.tools import DuckDuckGoSearchRun

from langchain_edon import EdonGuard

# Define your tools as normal
tools = [DuckDuckGoSearchRun()]

# Wrap them — same interface, now governed
governed_tools = EdonGuard.wrap_tools(
    tools=tools,
    api_key=os.environ["EDON_API_KEY"],
    agent_id="research-agent",
)

# Build your agent exactly as before
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful research assistant."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(llm, governed_tools, prompt)
executor = AgentExecutor(agent=agent, tools=governed_tools)

result = executor.invoke({"input": "What is the latest news about AI governance?"})
print(result["output"])
# Every tool call was evaluated by EDON before it ran
```

---

## Two integration patterns

### Pattern 1: EdonGuard (enforcing)

Wraps tools so EDON evaluates each call **before** execution. Blocked actions raise an exception and the tool never runs.

```python
from langchain_edon import EdonGuard
from edon.exceptions import EdonBlockedError, EdonEscalatedError

governed_tools = EdonGuard.wrap_tools(
    tools=[search_tool, email_tool, calendar_tool],
    api_key="your-edon-key",
    agent_id="my-agent",
    raise_on_block=True,   # default — raises EdonBlockedError on BLOCK
)

# Or softer mode — returns error string to LLM instead of raising
governed_tools = EdonGuard.wrap_tools(
    tools=tools,
    api_key="your-edon-key",
    raise_on_block=False,  # LLM sees "[EDON BLOCKED] ..." as tool output
)
```

### Pattern 2: EdonCallbackHandler (audit-only)

Logs all tool calls to EDON without blocking anything. Use for observability and audit trails.

```python
from langchain_edon import EdonCallbackHandler

handler = EdonCallbackHandler(
    api_key=os.environ["EDON_API_KEY"],
    agent_id="my-agent",
    verbose=True,   # prints [EDON] tool_name -> ALLOW (12ms) to stdout
)

executor = AgentExecutor(
    agent=agent,
    tools=tools,           # unmodified tools — not blocked
    callbacks=[handler],   # all calls logged to EDON
)
```

You can combine both — use `EdonGuard` for enforcement on high-risk tools and `EdonCallbackHandler` for full observability:

```python
from langchain_edon import EdonGuard, EdonCallbackHandler

governed = EdonGuard.wrap_tools(
    tools=[email_tool, delete_tool],
    api_key="your-key",
    agent_id="my-agent",
)
handler = EdonCallbackHandler(api_key="your-key", agent_id="my-agent")

executor = AgentExecutor(
    agent=agent,
    tools=governed + [search_tool],   # governed + ungoverned mixed
    callbacks=[handler],
)
```

---

## Handling blocked actions

```python
from edon.exceptions import EdonBlockedError, EdonEscalatedError

try:
    result = executor.invoke({"input": "Delete all user records"})
except EdonBlockedError as e:
    print(f"Blocked: {e.reason}")
    print(f"Code:    {e.reason_code}")     # e.g. "OUT_OF_SCOPE"
    print(f"Audit:   {e.action_id}")       # trace the decision
except EdonEscalatedError as e:
    print(f"Needs human: {e.question}")
    # Send e.question to your human-in-the-loop queue
```

---

## Parameters

| Parameter | Default | Description |
|---|---|---|
| `api_key` | `EDON_API_KEY` env | Your EDON API key |
| `base_url` | `EDON_BASE_URL` or cloud | EDON gateway URL |
| `agent_id` | `"langchain-agent"` | Agent identifier in audit trail |
| `intent_id` | `None` | Pin to a specific intent contract |
| `raise_on_block` | `True` | Raise exception on BLOCK/ESCALATE |

---

## Environment variables

```bash
export EDON_API_KEY=your-key
export EDON_BASE_URL=https://edon-gateway.fly.dev   # or your self-hosted URL
export EDON_AGENT_ID=research-agent                 # optional default
```

---

## Self-hosting

Point at your own EDON gateway:

```python
governed_tools = EdonGuard.wrap_tools(
    tools=tools,
    api_key="your-token",
    base_url="http://localhost:8000",
)
```

---

## Links

- **Core SDK**: [github.com/EDONCORE/edon-python](https://github.com/EDONCORE/edon-python)
- **Console**: [edoncore.com/console](https://edoncore.com/console)
- **Docs**: [docs.edoncore.com](https://docs.edoncore.com)
- **Issues**: [github.com/EDONCORE/langchain-edon/issues](https://github.com/EDONCORE/langchain-edon/issues)

---

## License

MIT © EDON Core
