Deterministic execution guard for AI agents: request-id dedup + finality gating + durable state.
Project description
SafeAgent
Execution guard for AI agent side effects that prevents duplicate execution across retries.
Demo
LLM agents retry tool calls.
That can duplicate side effects:
- payments
- emails
- trades
- tickets
- payouts
SafeAgent is designed to prevent duplicate execution of irreversible actions using request IDs and optional durable state, such as Postgres.
Install
pip install safeagent-exec-guard
Python 3.10+
Why this exists
AI systems retry operations constantly:
- agent loops retry tool calls
- HTTP clients retry failed requests
- queue workers replay jobs
- orchestrators restart workflows
Without protection:
retry -> duplicate payment
retry -> duplicate email
retry -> duplicate ticket
retry -> duplicate payout
SafeAgent inserts an execution guard between the decision and the irreversible action:
agent decision
↓
request_id generated
↓
SafeAgent execution guard
↓
side effect executes once
↓
future retries return cached receipt
Minimal Example
from safeagent_exec_guard import SettlementRequestRegistry
registry = SettlementRequestRegistry()
def send_email(payload):
print("SENDING EMAIL:", payload["to"])
receipt = registry.execute(
request_id="email:C123:invoice",
action="send_email",
payload={"to": "c123@example.com"},
execute_fn=send_email,
)
print(receipt)
Example output:
First call:
SENDING EMAIL: c123@example.com
{'ok': True, 'reason': 'executed', 'request_id': 'email:C123:invoice'}
Second call (retry):
{'ok': True, 'reason': 'dedup_same_request_id', 'request_id': 'email:C123:invoice'}
Running this twice only executes the side effect once. Later calls return the stored receipt.
Decorator API
from safeagent_exec_guard import SettlementRequestRegistry, safeagent_guard
registry = SettlementRequestRegistry()
@safeagent_guard(
registry=registry,
action="send_email",
request_id_fn=lambda payload: f"email:{payload['to']}:{payload.get('template','default')}",
)
def send_email(payload):
print("REAL SIDE EFFECT:", payload["to"])
send_email({"to": "user@example.com", "template": "invoice"})
send_email({"to": "user@example.com", "template": "invoice"})
The second call returns the cached receipt instead of executing again.
MCP Example
from safeagent_exec_guard import SettlementRequestRegistry
from safeagent_exec_guard.mcp import safe_mcp_tool
registry = SettlementRequestRegistry()
@safe_mcp_tool(
registry=registry,
action="send_payment",
request_id_fn=lambda payload: f"payment:{payload['recipient']}:{payload['amount']}",
)
def send_payment(amount: float, recipient: str):
print(f"REAL SIDE EFFECT: sending ${amount} to {recipient}")
Run:
python examples/mcp_retry_demo.py
Durable execution (Postgres)
SafeAgent can optionally use a Postgres-backed execution store.
This allows execution guarantees to hold across:
- process restarts
- multiple workers
- distributed systems
Without durable state, guarantees are limited to a single process.
Example:
from safeagent_exec_guard import SettlementRequestRegistry
from safeagent_exec_guard.postgres_store import PostgresExecutionStore
store = PostgresExecutionStore(
dsn="postgresql://postgres:postgres@localhost:5432/postgres"
)
registry = SettlementRequestRegistry(postgres_dsn="postgresql://postgres:postgres@localhost:5432/postgres")
def send_payment(payload):
print("REAL SIDE EFFECT:", payload)
registry.execute(
request_id="payment:alice:50",
action="send_payment",
payload={"amount": 50, "recipient": "alice"},
execute_fn=send_payment,
)
Run twice:
First run:
REAL SIDE EFFECT: {'amount': 50, 'recipient': 'alice'}
Second run:
Already executed: {'status': 'sent'}
Framework Examples
python examples/openai_tool_safeagent.py
python examples/langchain_safeagent.py
python examples/crewai_safeagent.py
python examples/decorator_safeagent.py
python examples/langchain_adapter_safeagent.py
python examples/mcp_retry_demo.py
python examples/postgres_demo.py
Failure semantics
SafeAgent records an execution receipt for each request_id.
Retry behavior
same request_id -> return stored receipt
The side effect is not executed again.
Timeout after execution
execution completed
response lost
caller retries
SafeAgent returns the stored receipt.
Partial failures
SafeAgent does not attempt automatic rollback.
Applications should handle partial commits using:
- audit logs
- reconciliation processes
- compensating actions
SafeAgent is designed to enforce at-most-once execution of irreversible actions, not business policy validation.
Run with Docker
Start Postgres:
docker compose up -d postgres
Run the Postgres demo:
docker compose run --rm safeagent python examples/postgres_demo.py
This uses a local Postgres container so execution receipts persist outside a single Python process.
License
Apache-2.0
Need help with agent reliability?
If you're building AI agents that trigger real-world actions such as payments, emails, or trades, retries can create duplicate execution and real risk.
If you're dealing with this in production or thinking about how to handle it, feel free to reach out.
Happy to:
- review your architecture
- help design execution safety layers
- implement SafeAgent-style guards in your system
This problem gets tricky quickly once retries and distributed systems are involved.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file safeagent_exec_guard-0.1.13.tar.gz.
File metadata
- Download URL: safeagent_exec_guard-0.1.13.tar.gz
- Upload date:
- Size: 84.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92a2e5d0cb41efb22f5a8a506421caf972696b552c6e7b9c96c1ae634369a6fe
|
|
| MD5 |
190c032f25b0181d7b706b511152af6b
|
|
| BLAKE2b-256 |
cf644f5ec9811acb867e8add35a1430412eee38bae64c36fe170c61144a807cd
|
File details
Details for the file safeagent_exec_guard-0.1.13-py3-none-any.whl.
File metadata
- Download URL: safeagent_exec_guard-0.1.13-py3-none-any.whl
- Upload date:
- Size: 26.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71190cf08b91133df9ee65f6e1812fc122cf55787d78edd4970bf4c9d5247d8c
|
|
| MD5 |
e7aab7734f36e98547ec3ae632d19c21
|
|
| BLAKE2b-256 |
e27ac70a09d42a06c48cb433f0bc5fee8c655bfbdfb809c90c3cc3ac976f700c
|