RDPGE
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.
Why RDPGE?
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. |
Key Ideas
- 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.
Install
pip install rdpge
Quick Start
import 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())
Using with Together AI
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=[...])
Using with Anthropic
from rdpge.llm import AnthropicAdapter, LLMConfig
llm = AnthropicAdapter(LLMConfig(
model="claude-sonnet-4-20250514",
api_key="sk-ant-...",
))
agent = Agent(llm=llm, tools=[...])
How It Works
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)
The Graph Manifest
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).
Context Blurring
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").
Signal Tools
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")
Multi-Turn Sessions
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")
Persistence
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]: ...
Event Hooks
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
Execution Traces
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"],
# }
API Reference
Agent
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
AgentResult
@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()
@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:
...
Architecture
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.
License
MIT
Author
Jahanzeb Ahmed — GitHub
Metadata
Release files for rdpge 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| rdpge-0.2.0.tar.gz | 34.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rdpge-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 68.9 kB
Release files / rdpge-0.2.0.tar.gz
| Download URL | rdpge-0.2.0.tar.gz |
|---|---|
| Size | 34.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1659f5d8cb61b898470daa3803b3aa5e8642896569bd95aa6ff373a957502d5e
|
|
BLAKE2b-256 checksum How to use checksums |
c97327cae6818253d59148fd99696c83c04f7bcd3622c95a6d6e2211725eb5c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 16, 2026.
Transparency logRelease files / rdpge-0.2.0-py3-none-any.whl
| Download URL | rdpge-0.2.0-py3-none-any.whl |
|---|---|
| Size | 34.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5c338e226b7101a306a946035e32a65b9183fe4d110ef44af1dbd607dc9804a5
|
|
BLAKE2b-256 checksum How to use checksums |
44576676726b2572275536a255d9451f5b95aaf9f64c8f3fea5e0029d14e1ae4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 16, 2026.
Transparency logSecurity for rdpge 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for rdpge-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 16, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.