This document specifies a clean separation between Agent-side code (your LangGraph app) and Server-side logic (Open Edison).
- Agent (A): wraps your LangGraph tools to ask OE for permission before execution, and reports completion afterwards. The Agent mints/provides its own session id.
- Server (S): Open Edison. Applies the standard permissions/trifecta gating and persists calls to
sessions.db. Approvals happen via the dashboard.
POST /agent/session(optional): ensure a session exists.POST /agent/begin: pre-call permission check and pending-call registration.POST /agent/end: post-call status/duration/result update.
All routes are API-key protected (same dependency as other management endpoints). Calls are persisted to the same tables and raise the same events as MCP tool calls.
- Begin request:
{ session_id?: str, name: str, args_summary?: str, timeout_s?: float }session_idmay be omitted; the server will mint one if not provided.
- Name is normalized to
agent_<function_name>.- Response:
{ ok: bool, session_id: str, call_id: str|null, approved: bool|null, error: str|null }.
- Response:
- End request:
{ session_id: str, call_id: str, status: "ok"|"error", duration_ms?: float, result_summary?: str }.
- Session handling
- Contextvar stores current
session_id. If absent, mint UUIDv4 and set. - Per-call override: pass
__edison_session_id="..."to the wrapped function.
- Contextvar stores current
- Decorator
@edison.track(name?: str)- Before body: POST
/agent/beginand block for approval (with timeout). On deny/timeout → raisePermissionError. - After body: enqueue POST
/agent/endvia a background worker (with retry backoff). - Preserves function metadata via
functools.wrapsso LangGraph/@toolworks.
- Before body: POST
- Healthcheck on init (optional)
- Logs if
/healthunreachable or API key invalid on/mcp/status.
- Logs if
- Tracked functions are treated as tools named
agent_<function_name>. - Configure permissions under an
agentsection intool_permissions.jsonusing the sameagent_<name>keys. - Server reuses
DataAccessTrackerfor lethal-trifecta and other policy checks.
- Reuse
MCPSessionandToolCallmodels. Calls appear in the dashboard timeline. - Parameters store
summary(fromargs_summary) andresult_summary(fromresult_summary). - Previews are capped at 1,000,000 characters; no redaction by default.
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from open_edison import Edison
edison = Edison() # uses OPEN_EDISON_API_BASE and OPEN_EDISON_API_KEY
@tool
@edison.track()
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
llm = ChatOpenAI()
llm_with_tools = edison.bind_tools(llm, [multiply])
# Invoke your graph/model with llm_with_tools- The
/agent/*routes are mounted alongside existing management routes and reuse:get_session_from_db,create_db_session,MCPSessionModelDataAccessTracker(permissions/trifecta),events.wait_for_approvalrecord_tool_call,sessions_db_changedemission
- Server down/unhealthy → begin raises
RuntimeError(function not executed). - Approval denied/timeout → begin returns approved=false and client raises
PermissionError. - End reports are idempotent on
call_id; background worker retries with backoff.
- Approvals are handled in the dashboard; no client-side approval calls.
- Agent does not start MCP servers; it only talks to management API.
- MCP tool calls and agent calls are unified in
sessions.dband the dashboard.