See LangGraph docs for the more about LangGraph and associated libraries:
pip install -U langgraph langchain-openai open-edisonSet environment variables:
OPENAI_API_KEY= your OpenAI keyOPEN_EDISON_API_KEY= your Open Edison API keyOPEN_EDISON_API_BASE=http://localhost:3001(default)
make runAccess the Open Edison dashboard: http://localhost:3001/dashboard
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from open_edison import Edison
# Edison reads OPEN_EDISON_API_BASE / OPEN_EDISON_API_KEY from env
edison = Edison()
@tool
@edison.track() # auto-names: agent_web_search
def web_search(query: str, max_results: int = 3) -> str:
"""Return up to N result URLs (demo)."""
return "https://docs.python.org/3/"
@tool
@edison.track() # auto-names: agent_fetch_url
def fetch_url(url: str, max_chars: int = 1000) -> str:
"""Fetch and return the first max_chars of the page."""
import httpx
return httpx.get(url, follow_redirects=True, timeout=10).text[:max_chars]
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
agent = create_react_agent(model=llm, tools=[web_search, fetch_url])
result = agent.invoke({
"messages": [("user", "Fetch the first 1000 chars of the CPython docs homepage.")]
})
print(result["messages"][-1].content)diff agent_no_firewall.py agent_firewall.pyexamples/langgraph/agent_no_firewall.py examples/langgraph/agent_firewall.py
from open_edison import Edison
edison = Edison()
@tool @tool
@edison.track() # auto-names: agent_web_search
def web_search(query: str, _max_results: int = 3) -> str: def web_search(query: str, _max_results: int = 3) -> str:
--- ---
@tool @tool
@edison.track() # auto-names: agent_fetch_url
def fetch_url(url: str, _max_chars: int = 1000) -> str: def fetch_url(url: str, _max_chars: int = 1000) -> str:
Tracked tools are named agent_<function_name>. Configure under the agent section in tool_permissions.json:
{
"agent": {
"web_search": {
"enabled": true,
"write_operation": false,
"read_private_data": false,
"read_untrusted_public_data": true,
"acl": "SECRET"
},
"fetch_url": {
"enabled": true,
"write_operation": false,
"read_private_data": true,
"read_untrusted_public_data": true,
"acl": "SECRET"
}
}
}Open Edison enforces:
- Lethal trifecta prevention (private data + untrusted exposure + write)
- ACL write-downgrade blocking
- Manual approvals via the dashboard
- Pre-call:
/agent/begin(gating + possible approval wait) - Post-call:
/agent/end(status, duration, result preview) - Arguments/results are captured as JSON previews (capped at 1,000,000 chars).
- 401 Invalid API key: check
OPEN_EDISON_API_KEYand server is running. - Tool blocked: verify
tool_permissions.jsonand approve in dashboard if needed.