A State-Aware Rollback and Trajectory-Replanning Framework for Autonomous LLM Agents
Project description
๐ก๏ธ DriftGuard
A State-Aware Rollback and Trajectory-Replanning Framework for Autonomous LLM Agents
Installation โข Quickstart โข How it Works โข API Reference โข Integrations
DriftGuard wraps any LLM agent executor with a causal state graph, automatic divergence detection, rollback to the last safe state, and failure-context-aware replanning โ so your agents recover from mid-chain errors without full restarts.
The Problem
Agents in multi-step tasks make errors mid-chain (tool failures, goal drift, infinite loops) and have no way to recover without a full restart. This wastes tokens, time, and context.
The Solution
DriftGuard models an agent run as a causal graph of state transitions:
S0 โ S1 โ S2 โ S3 (๐ฅ error)
โ rollback โ S2 โ S4 (โ
success)
When divergence is detected, the system:
- Identifies the failure via pluggable detectors
- Rolls back to the last causally-safe state
- Replans with failure context injected into the next prompt
- Resumes โ the agent tries a different strategy
Installation
pip install agents-driftguard
With optional backends:
# Local embeddings (sentence-transformers)
pip install agents-driftguard[embeddings]
# OpenAI embeddings + function-calling adapter
pip install agents-driftguard[openai]
# LangChain integration
pip install agents-driftguard[langchain]
# Development
pip install agents-driftguard[dev]
Quickstart
from agents_driftguard import AgentUndoWrapper
# Your agent is just a callable: (prompt: str) -> str
def my_agent(prompt: str) -> str:
# Call your LLM here
return llm.generate(prompt)
# Wrap it with DriftGuard
wrapper = AgentUndoWrapper(
executor=my_agent,
max_rollbacks=3,
detectors=["goal_drift", "tool_failure", "loop"],
embedding_backend="dummy", # or "sentence-transformers" / "openai"
)
# Run with automatic rollback protection
result = wrapper.run(goal="Research and summarize recent AI papers")
print(result.success) # True/False
print(result.final_output) # The agent's final answer
print(result.rollbacks_performed) # Number of rollbacks that occurred
print(result.causal_graph_mermaid) # Mermaid diagram of the state graph
How it Works
Execution Loop
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AgentUndoWrapper โ
โ โ
โ 1. Call executor(prompt) โ
โ 2. Parse action + observation โ AgentState โ
โ 3. Embed current context โ state_embedding โ
โ 4. Add to CausalGraph โ
โ 5. Run DivergenceDetector โ
โ 6. If divergence detected: โ
โ a. Mark node diverged โ
โ b. Find safe rollback point โ
โ c. RollbackController.rollback() โ
โ d. Replanner.replan() โ inject context โ
โ e. Resume from safe state โ
โ 7. Repeat until done or max_rollbacks โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Divergence Detectors
| Detector | What it catches | How |
|---|---|---|
GoalDriftDetector |
Agent wandering off-task | Cosine similarity between goal and state embeddings |
ToolFailureDetector |
Tool errors and crashes | Regex patterns in observations (errors, tracebacks, HTTP codes) |
LoopDetector |
Infinite loops | State hash deduplication over a sliding window |
ConstraintChecker |
Business rule violations | User-defined Python lambdas |
LLMJudge |
Subtle misalignment | Optional LLM-based scoring |
OutputQualityDetector |
Suspiciously poor outputs | Checking length and word repetition ratio |
TokenBudgetDetector |
Excessive API usage | Whitespace-based token estimation across state history |
HallucinationDetector |
Made-up information | Flagging confident uncertainty or apology patterns |
Detectors are combined with configurable strategies: "any" (default), "all", or "weighted".
Causal Graph
Every agent run produces a causal DAG:
flowchart TD
classDef safe fill:#2d6a4f,stroke:#1b4332,color:#fff
classDef diverged fill:#d00000,stroke:#6a040f,color:#fff
S0["S0: __start__"]:::safe
S1["S1: search"]:::safe
S2["S2: compute"]:::safe
S3["S3: write_file"]:::diverged
S4["S4: output"]:::safe
S0 --> S1
S1 --> S2
S2 --> S3
S2 --> S4
Dependency-Aware Rollback Traversal
Unlike naive sequential rollback systems, DriftGuard tracks resource inputs and outputs (e.g. specific files, SQL tables, code modules). When a tool failure signal registers a failed_resource (for instance, a SyntaxError in utils.py), DriftGuard:
- Performs backwards graph traversal along causal ancestors.
- Identifies the exact ancestor step that modified or created the failed resource.
- Selects the step immediately preceding that ancestor as the target recovery state.
- Unwinds the side-effects of all intermediate steps in reverse chronological order using their registered
@reversiblecompensating hooks, preserving unrelated execution branches.
Replanning
After rollback, the agent receives failure context:
=== ROLLBACK CONTEXT ===
You previously attempted: write_file(path='/protected/path')
This failed because: A tool call returned an error or unexpected result.
You have been rolled back to step 2.
Original goal: Analyze data and produce a summary report
Actions that led to failure (do NOT repeat this approach):
- Step 3: write_file โ 'Error: Permission denied'
Try a different strategy.
=== END ROLLBACK CONTEXT ===
API Reference
AgentUndoWrapper
wrapper = AgentUndoWrapper(
executor=my_fn, # callable: (str) -> str
max_rollbacks=3, # max rollback attempts
detectors=["goal_drift", "tool_failure", "loop"],
goal_drift_threshold=0.75, # cosine similarity threshold
store="memory", # "memory" | "sqlite"
constraints=[lambda s: ...], # user-defined validators
on_rollback=callback_fn, # optional rollback hook
embedding_backend="dummy", # "dummy" | "sentence-transformers" | "openai"
max_steps=50, # safety limit
verbose=False,
)
result = wrapper.run(goal="your task")
AgentRunResult
| Field | Type | Description |
|---|---|---|
success |
bool |
Whether the agent completed successfully |
final_output |
str |
The agent's final answer |
total_steps |
int |
Total steps executed |
rollbacks_performed |
int |
Number of rollbacks |
causal_graph_mermaid |
str |
Mermaid diagram string |
rollback_history |
list[RollbackResult] |
Detailed rollback logs |
@reversible Decorator
Register undo functions for tools with side-effects:
from agents_driftguard import reversible
def undo_write(args, result):
os.remove(args["path"])
@reversible(undo_fn=undo_write, tool_name="write_file")
def write_file(path: str, content: str) -> str:
with open(path, "w") as f:
f.write(content)
return f"Written to {path}"
During rollback, undo_write is automatically called to reverse the side-effect.
Async Support
DriftGuard natively supports asynchronous agent execution using AsyncAgentUndoWrapper.
import asyncio
from agents_driftguard.async_wrapper import AsyncAgentUndoWrapper
async def my_async_agent(prompt: str) -> str:
# Await your LLM call here
return await async_llm.generate(prompt)
async def main():
wrapper = AsyncAgentUndoWrapper(executor=my_async_agent)
result = await wrapper.arun(goal="Fetch async data")
print(result.success)
asyncio.run(main())
Live Web Dashboard
Launch the zero-dependency, local web dashboard to view telemetry in real-time.
from agents_driftguard.dashboard.app import start_dashboard_server
# Start the dashboard in the background
start_dashboard_server(port=8050)
# Then run your agent
wrapper.run("Do work")
Navigate to http://localhost:8050 in your browser to see your agent's timeline, causal graph visualization, and rollback events as they happen!
Integrations
LangChain
from langchain.agents import AgentExecutor
from agents_driftguard.integrations.langchain import LangChainAdapter
executor = AgentExecutor(agent=..., tools=...)
adapter = LangChainAdapter(executor)
wrapper = AgentUndoWrapper(
executor=adapter,
step_parser=adapter.parse_step,
)
OpenAI Function Calling
from openai import OpenAI
from agents_driftguard.integrations.openai import OpenAIFunctionCallingAdapter
client = OpenAI()
adapter = OpenAIFunctionCallingAdapter(
client=client,
model="gpt-4o",
tools=[...],
tool_executor=my_tool_runner,
)
wrapper = AgentUndoWrapper(
executor=adapter,
step_parser=adapter.parse_step,
)
State Stores
| Store | Backend | Persistence | Use Case |
|---|---|---|---|
InMemoryStateStore |
Python dict | No | Development, testing |
SQLiteStateStore |
SQLite (stdlib) | Yes | Production, debugging |
# SQLite store
wrapper = AgentUndoWrapper(executor=fn, store="sqlite")
# Or bring your own
from agents_driftguard.store.sqlite import SQLiteStateStore
store = SQLiteStateStore(db_path="agent_states.db")
wrapper = AgentUndoWrapper(executor=fn, store=store)
Development
# Install in development mode
pip install -e ".[dev]"
# Run tests
pytest agents_driftguard/tests/ -v
# Format
black agents_driftguard/
# Lint
ruff check agents_driftguard/
Architecture
agents_driftguard/
โโโ __init__.py # AgentUndoWrapper main API
โโโ core/
โ โโโ state.py # AgentState + StateStore protocol
โ โโโ graph.py # CausalGraph (NetworkX DAG)
โ โโโ detector.py # DivergenceDetector + sub-detectors
โ โโโ rollback.py # RollbackController + @reversible
โ โโโ replanner.py # Failure-context injection
โโโ integrations/
โ โโโ base.py # Abstract adapter interface
โ โโโ langchain.py # LangChain adapter
โ โโโ openai.py # OpenAI function-calling adapter
โโโ store/
โ โโโ memory.py # In-memory StateStore
โ โโโ sqlite.py # SQLite StateStore
โโโ utils/
โ โโโ embeddings.py # Embedding backends
โ โโโ visualize.py # Mermaid graph export
โ โโโ hashing.py # Deterministic state hashing
โโโ tests/
โโโ test_state.py
โโโ test_graph.py
โโโ test_detector.py
โโโ test_rollback.py
โโโ test_wrapper.py # End-to-end mock agent test
Research Paper & Citation
If you use this framework in your research, please cite our paper:
@article{driftguard2026,
title={DriftGuard: A State-Aware Rollback and Trajectory-Replanning Framework for Autonomous LLM Agents},
author={Sanjoy Kumar},
journal={Preprint / Working Paper},
year={2026}
}
License
MIT
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 agents_driftguard-1.1.0.tar.gz.
File metadata
- Download URL: agents_driftguard-1.1.0.tar.gz
- Upload date:
- Size: 59.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8cb6d5576b62a7e0e253c9cc2c8dca3d378e065fbe6aad842872759623fa544
|
|
| MD5 |
5fb7f500f023e152f827842b315cb507
|
|
| BLAKE2b-256 |
6cac2cd5bdbe3dac2010e535e43b01dddf5555dc2c8f5f61041255a7a7c731a7
|
File details
Details for the file agents_driftguard-1.1.0-py3-none-any.whl.
File metadata
- Download URL: agents_driftguard-1.1.0-py3-none-any.whl
- Upload date:
- Size: 64.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62662b67c4b638d33970fdf13825e4d50a989af837df22ca3416a6876104cb43
|
|
| MD5 |
f0ece0897138520da848acaca750d1f3
|
|
| BLAKE2b-256 |
a06fa4f9f704acb4836b6f085e2b8d1d0abaa1c04f260701b001d19d24377533
|