Runtime Dynamic & Probabilistic Graph Execution
A novel agentic AI framework that treats LLM outputs as probabilistic events, not deterministic programs.
RDPGE replaces the flat ReAct loop with a dynamic execution graph — giving agents structured memory, selective context, and real-time situational awareness.
Standard agentic frameworks (ReAct, function-calling loops) suffer from three core problems:
| Problem | What Happens | RDPGE's Solution |
|---|---|---|
| Myopia | The agent only sees recent context. Work done 15 steps ago fades from attention. | Graph Manifest — a live dashboard showing all tasks, distances, references, and step budget. Updated every turn. |
| Greedy execution | The agent does the first thing that seems useful without considering the bigger picture. | Task-based organization — work is structured into named tasks. The agent sees the full map before acting. |
| Context waste | All tool outputs stay in context forever, consuming tokens even when irrelevant. | Context blurring — inactive tasks' tool outputs are replaced with [BLURRED]. Restored on demand via edges. |
- Code-as-interface — The LLM outputs Python code, not JSON tool calls. Comments serve as chain-of-thought. An
actiondictionary is the structured interface. - Probabilistic graph — Execution is tracked as a dynamic graph of nodes organized by tasks. The LLM creates tasks and nodes as needed.
- Context blurring — Only the active task's tool outputs are visible. Everything else is
[BLURRED]. The LLM can restore any task's context by creating an edge. - Graph manifest — Every turn, the LLM sees a live dashboard: active node, current task, step budget, task distances, and inter-task references.
- Signal tools — Built-in tools (
complete,ask_user,surrender) that control execution flow explicitly.
pip install rdpgeimport asyncio
from rdpge import Agent, tool
from rdpge.llm import OpenAIAdapter, LLMConfig
# 1. Define tools
@tool()
def read_file(path: str) -> str:
"""Read file contents from disk."""
with open(path) as f:
return f.read()
@tool()
def write_file(path: str, content: str) -> str:
"""Write content to a file on disk."""
with open(path, "w") as f:
f.write(content)
return f"Written {len(content)} bytes to {path}"
# 2. Create agent
agent = Agent(
llm=OpenAIAdapter(LLMConfig(
model="gpt-4o",
api_key="sk-...",
)),
tools=[read_file, write_file],
instructions="You are a code assistant.",
max_steps=25,
)
# 3. Run
async def main():
result = await agent.run("Read auth.py and fix the login bug")
print(f"Status: {result.status}")
print(f"Steps used: {result.steps}")
print(f"Reason: {result.reason}")
asyncio.run(main())from rdpge.llm import OpenAIAdapter, LLMConfig
llm = OpenAIAdapter(LLMConfig(
model="Qwen/Qwen3-Coder-480B-A35B-Instruct",
api_key="your-together-key",
base_url="https://api.together.xyz/v1",
))
agent = Agent(llm=llm, tools=[...])from rdpge.llm import AnthropicAdapter, LLMConfig
llm = AnthropicAdapter(LLMConfig(
model="claude-sonnet-4-20250514",
api_key="sk-ant-...",
))
agent = Agent(llm=llm, tools=[...])User Request
│
▼
┌─────────────────────────────────────────────┐
│ EXECUTION LOOP │
│ │
│ 1. Build Context │
│ ├── System Prompt │
│ ├── Graph Manifest (live dashboard) │
│ └── Node History (with blurring) │
│ │
│ 2. LLM Generates Python Code │
│ └── action = {node, reason, tool_call} │
│ │
│ 3. Execute Code in Sandbox │
│ └── Extract action dict │
│ │
│ 4. Route Tool Call │
│ ├── Signal tool? → Handle internally │
│ └── Regular tool? → Execute via registry│
│ │
│ 5. Update Graph │
│ ├── Record node in task │
│ ├── Apply blurring to inactive tasks │
│ └── Save state (multi-turn) │
│ │
│ 6. Loop until: complete / surrender / │
│ ask_user / max_steps │
└─────────────────────────────────────────────┘
│
▼
AgentResult(status, reason, steps, trace, graph)
Every turn, the LLM sees this dashboard in its context:
{
"tasks": {
"a": {
"status": "inactive",
"steps": 3,
"distance": 2,
"references": 0
},
"b": {
"status": "active",
"steps": 2
"distance": 0,
"references": 0
}
},
"edges": [],
"runtime": {
"step": 6,
"active_node": "node-b2",
"current_task": "b",
"restored_context": null
}
}- Distance tells the LLM how far back a task is (recency).
- References show inter-task dependencies (importance).
- Step counter shows remaining budget (the hard execution limit).
When the LLM switches from Task A to Task B:
# Task A's tool outputs become:
Tool: [BLURRED]
# Task B's tool outputs remain fully visible:
Tool: def login(user, pwd): ...
The LLM can restore Task A's context by calling restore_context(task="a").
Built-in tools that control execution flow:
| Signal | Args | Effect |
|---|---|---|
complete |
{} |
Task is done. Loop ends. |
ask_user |
{"question": str} |
Pauses execution. Returns the question to the caller. |
surrender |
{"reason": str} |
Cannot accomplish the task. Loop ends. |
Developer-side abort:
# From a UI button or hook callback:
agent.abort("User pressed cancel")RDPGE preserves full graph state between conversations:
# Turn 1
result = await agent.run("Read the codebase and find bugs")
# result.status == "awaiting_input" (agent used ask_user)
# Turn 2 — agent remembers everything from Turn 1
result = await agent.run("Focus on auth.py")from rdpge import Agent, InMemoryStore
# In-memory (default)
agent = Agent(llm=llm, tools=[...], store=InMemoryStore())
# Custom store (Redis, database, etc.)
# Implement the SessionStore protocol:
class RedisStore:
async def save(self, session_id: str, data: dict) -> None: ...
async def load(self, session_id: str) -> dict | None: ...
async def delete(self, session_id: str) -> None: ...
async def list_sessions(self) -> list[str]: ...Monitor and react to agent behavior:
@agent.on("step_end")
async def log_step(data):
print(f"Step {data['step']}: {data['node_id']} → {data['tool']}")
@agent.on("complete")
async def on_done(data):
print(f"Finished in {data['steps']} steps")
@agent.on("surrender")
async def on_surrender(data):
print(f"Gave up: {data['reason']}")Available events: step_start, step_end, tool_called, complete, ask_user, surrender, abort, error
Every run produces a detailed trace:
result = await agent.run("Fix the bug")
summary = result.trace.summary()
print(summary)
# {
# "session_id": "a1b2c3d4",
# "total_steps": 5,
# "total_duration_ms": 12340,
# "tools_used": {"read_file": 2, "write_file": 1, "complete": 1, ...},
# "nodes": ["node-a1", "node-a2", "node-a3", "node-b1", "node-b2"],
# }Agent(
llm, # LLMProvider instance
tools: list = None, # List of @tool() or BaseTool instances
instructions: str = "", # Domain-specific instructions for the LLM
instructions_file: str = None,# Or load instructions from a file
max_steps: int = 25, # Hard execution limit
store = None, # SessionStore for persistence
signal_handlers: dict = None, # Override signal tool behavior
)Methods:
await agent.run(request)→AgentResultagent.abort(reason)— stop execution from outsideagent.new_session()— start freshawait agent.load_session(session_id)→boolagent.on(event)— decorator for event hooks
@dataclass
class AgentResult:
success: bool # True if task completed successfully
status: str # "completed" | "awaiting_input" | "surrendered" | "aborted" | "max_steps" | "error"
reason: str # Human-readable summary
steps: int # Number of steps executed
session_id: str # Session identifier
trace: SessionTrace # Execution trace
graph: GraphState # Final graph state
error: str = "" # Error details (if status == "error")@tool()
def my_tool(param: str) -> str:
"""Tool description (used in the LLM prompt)."""
return result
# Or with explicit description:
@tool("Override the docstring description")
def my_tool(param: str) -> str:
...RDPGE is built on four principles:
-
Respect probabilistic nature — LLM outputs are unpredictable. The framework handles malformed outputs, retries, and edge cases structurally.
-
Overcome myopia — The graph manifest gives the LLM a bird's-eye view of its entire session, preventing short-sighted decisions.
-
Ensure task accuracy — Signal tools (
surrender,ask_user) let the agent be honest about its limitations instead of producing garbage output. -
Complete observability — Traces, hooks, and graph export provide full transparency into agent behavior at every level.
MIT
Jahanzeb Ahmed — GitHub