Skip to main content

Procedural memory + REPL context package with DSPy 3.0 integration for autonomous agents

Project description

rec-praxis-rlm

Procedural Memory + REPL Context for Autonomous AI Agents

A Python package that provides persistent procedural memory and safe code execution capabilities for DSPy 3.0 autonomous agents, enabling experience-based learning and programmatic document manipulation.

PyPI version Python 3.10+ Tests Test Coverage Code Style: Black License: MIT

Features

  • Procedural Memory: Store and retrieve agent experiences with hybrid similarity scoring (environmental + goal embeddings)
  • FAISS Indexing: 10-100x faster retrieval at scale (>10k experiences)
  • RLM Context: Programmatic document inspection (grep, peek, head, tail) with ReDoS protection
  • Safe Code Execution: Sandboxed Python REPL with AST validation and restricted builtins
  • DSPy 3.0 Integration: Autonomous planning with ReAct agents and integrated tools
  • MLflow Observability: Automatic tracing and experiment tracking
  • Production Ready: 99.38% test coverage, comprehensive error handling, backward-compatible storage versioning

Requirements

Core Features (No API Key Required)

The following features work out-of-the-box without any API keys:

  • Procedural Memory: Uses local sentence-transformers for embeddings
  • RLM Context: Document inspection (grep, peek, head, tail) and safe code execution
  • FAISS Indexing: Optional performance optimization for large-scale retrieval

Optional Features (API Key Required)

  • DSPy Autonomous Planning: Requires an API key from one of these providers:
    • Groq (recommended - fast and free): export GROQ_API_KEY="gsk-..."
    • OpenAI: export OPENAI_API_KEY="sk-..."
    • OpenRouter (access to many models): export OPENROUTER_API_KEY="sk-or-..."
    • Any LiteLLM-supported provider

Quick Start

Installation

# Basic installation (works without API key)
pip install rec-praxis-rlm

# With all optional dependencies (FAISS, OpenAI, async support)
pip install rec-praxis-rlm[all]

# Development installation
pip install rec-praxis-rlm[dev]

Example 1: Procedural Memory

from rec_praxis_rlm.memory import ProceduralMemory, Experience
from rec_praxis_rlm.config import MemoryConfig

# Initialize memory
config = MemoryConfig(storage_path="./agent_memory.jsonl")
memory = ProceduralMemory(config)

# Store experiences
memory.store(Experience(
    env_features=["web_scraping", "python", "beautifulsoup"],
    goal="extract product prices from e-commerce site",
    action="Used BeautifulSoup with CSS selectors for price elements",
    result="Successfully extracted 1000 prices with 99% accuracy",
    success=True
))

# Recall similar experiences
experiences = memory.recall(
    env_features=["web_scraping", "python"],
    goal="extract data from website",
    top_k=5
)

for exp in experiences:
    print(f"Similarity: {exp.similarity_score:.2f}")
    print(f"Action: {exp.action}")
    print(f"Result: {exp.result}\n")

Example 2: RLM Context for Document Inspection

from rec_praxis_rlm.rlm import RLMContext
from rec_praxis_rlm.config import ReplConfig

# Initialize context
config = ReplConfig()
context = RLMContext(config)

# Add documents
with open("application.log", "r") as f:
    context.add_document("app_log", f.read())

# Search for patterns
matches = context.grep(r"ERROR.*database", doc_id="app_log")
for match in matches:
    print(f"Line {match.line_number}: {match.match_text}")
    print(f"Context: ...{match.context_before}{match.match_text}{match.context_after}...")

# Extract specific ranges
error_section = context.peek("app_log", start_char=1000, end_char=2000)

# Get first/last N lines
recent_logs = context.tail("app_log", n_lines=50)

Example 3: Safe Code Execution

from rec_praxis_rlm.rlm import RLMContext

context = RLMContext()

# Execute safe code
result = context.safe_exec("""
total = 0
for i in range(10):
    total += i * 2
total
""")

if result.success:
    print(f"Output: {result.output}")
    print(f"Execution time: {result.execution_time_seconds:.3f}s")
else:
    print(f"Error: {result.error}")

# Prohibited operations are blocked
result = context.safe_exec("import os; os.system('rm -rf /')")
# Result: ExecutionError - Import statements not allowed

Example 4: Autonomous Planning with DSPy

from rec_praxis_rlm.dspy_agent import PraxisRLMPlanner
from rec_praxis_rlm.memory import ProceduralMemory
from rec_praxis_rlm.config import PlannerConfig, MemoryConfig

# Initialize memory and planner
memory = ProceduralMemory(MemoryConfig())

# Option 1: Programmatic API key (recommended for Groq)
planner = PraxisRLMPlanner(
    memory=memory,
    config=PlannerConfig(
        lm_model="groq/llama-3.3-70b-versatile",
        api_key="gsk-..."  # Pass key directly
    )
)

# Option 2: Environment variables (works for all providers)
# import os
# os.environ["GROQ_API_KEY"] = "gsk-..."
# planner = PraxisRLMPlanner(
#     memory=memory,
#     config=PlannerConfig(lm_model="groq/llama-3.3-70b-versatile")
# )

# Option 3: OpenAI with programmatic key
# planner = PraxisRLMPlanner(
#     memory=memory,
#     config=PlannerConfig(
#         lm_model="openai/gpt-4o-mini",
#         api_key="sk-..."
#     )
# )

# Option 4: OpenRouter with programmatic key
# planner = PraxisRLMPlanner(
#     memory=memory,
#     config=PlannerConfig(
#         lm_model="openrouter/meta-llama/llama-3.2-3b-instruct:free",
#         api_key="sk-or-..."
#     )
# )

# Add context for document inspection
from rec_praxis_rlm.rlm import RLMContext
context = RLMContext()
context.add_document("logs", open("server.log").read())
planner.add_context(context, "server_logs")

# Autonomous planning
answer = planner.plan(
    goal="Analyze server errors and suggest fixes",
    env_features=["production", "high_traffic", "database"]
)
print(answer)

Architecture

┌─────────────────────────────────────────┐
│     PraxisRLMPlanner (DSPy ReAct)       │
│   Autonomous decision-making layer      │
├─────────────────┬───────────────────────┤
│                 │                       │
│    Tools        │    Tools              │
│                 │                       │
▼                 ▼                       ▼
┌─────────────┐  ┌──────────────┐  ┌─────────────┐
│ Procedural  │  │  RLMContext  │  │   External  │
│   Memory    │  │   (Facade)   │  │    APIs     │
├─────────────┤  ├──────────────┤  └─────────────┘
│ • recall()  │  │ DocumentStore│
│ • store()   │  │ DocSearcher  │
│ • compact() │  │ CodeExecutor │
├─────────────┤  └──────────────┘
│ Embeddings  │
│ ┌─────────┐ │
│ │ Local   │ │  FAISS Index (optional)
│ │ API     │ │  ┌──────────────┐
│ │ Jaccard │◄─┼──┤ 10-100x      │
│ └─────────┘ │  │ faster search│
└─────────────┘  └──────────────┘
       │
       ▼
  Storage (JSONL)
  • Append-only
  • Versioned
  • Crash-safe

Performance

Operation Without FAISS With FAISS Speedup
Recall (100 exp) ~2ms ~2ms 1x
Recall (1,000 exp) ~20ms ~3ms 6.7x
Recall (10,000 exp) ~200ms ~20ms 10x
Recall (100,000 exp) ~2000ms ~20ms 100x
Operation Performance Notes
Document grep (10MB) <500ms With ReDoS protection
Safe code execution <100ms Sandboxed environment
Memory loading (10k exp) <1s With lazy loading

Supported LLM Providers

For DSPy autonomous planning, rec-praxis-rlm supports any LiteLLM-compatible provider:

Groq (Recommended)

Fast, free API with high rate limits.

import os
os.environ["GROQ_API_KEY"] = "gsk-..."

planner = PraxisRLMPlanner(
    memory=memory,
    config=PlannerConfig(lm_model="groq/llama-3.3-70b-versatile")
)

Available models: llama-3.3-70b-versatile, mixtral-8x7b-32768, gemma2-9b-it

OpenAI

Industry standard with highest quality models.

import os
os.environ["OPENAI_API_KEY"] = "sk-..."

planner = PraxisRLMPlanner(
    memory=memory,
    config=PlannerConfig(lm_model="openai/gpt-4o-mini")
)

Available models: gpt-4o-mini, gpt-4o, gpt-4-turbo, gpt-3.5-turbo

OpenRouter

Access to 200+ models from multiple providers.

import os
os.environ["OPENROUTER_API_KEY"] = "sk-or-..."

planner = PraxisRLMPlanner(
    memory=memory,
    config=PlannerConfig(lm_model="openrouter/meta-llama/llama-3.2-3b-instruct:free")
)

Available models: See OpenRouter models

Other Providers

Any LiteLLM-supported provider works: Anthropic, Cohere, Azure, AWS Bedrock, etc.

# Anthropic Claude
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-..."
planner = PraxisRLMPlanner(
    memory=memory,
    config=PlannerConfig(lm_model="anthropic/claude-3-5-sonnet-20241022")
)

See LiteLLM providers for full list.

Configuration

Memory Configuration

from rec_praxis_rlm.config import MemoryConfig

config = MemoryConfig(
    storage_path="./memory.jsonl",
    top_k=6,                          # Number of experiences to retrieve
    similarity_threshold=0.5,         # Minimum similarity score
    env_weight=0.6,                   # Weight for environmental features
    goal_weight=0.4,                  # Weight for goal similarity
    require_success=False,            # Only retrieve successful experiences
    embedding_model="sentence-transformers/all-MiniLM-L6-v2",
    result_size_limit=50000           # Max result size in bytes
)

REPL Configuration

from rec_praxis_rlm.config import ReplConfig

config = ReplConfig(
    max_output_chars=10000,           # Max output capture
    max_search_matches=100,           # Max grep results
    search_context_chars=200,         # Context before/after match
    execution_timeout_seconds=5.0,    # Code execution timeout
    enable_sandbox=True,              # Use sandboxed execution
    log_executions=True,              # Log for audit trail
    allowed_builtins=[                # Allowed built-in functions
        "len", "range", "sum", "max", "min", "sorted", ...
    ]
)

Planner Configuration

from rec_praxis_rlm.config import PlannerConfig

config = PlannerConfig(
    lm_model="openai/gpt-4o-mini",    # Language model
    api_key="sk-...",                  # Optional API key (or use env vars)
    temperature=0.0,                   # Sampling temperature
    max_iters=10,                      # Max ReAct iterations
    enable_mlflow_tracing=True,        # MLflow observability
    optimizer="miprov2",               # DSPy optimizer
    optimizer_auto_level="medium"      # Automation level
)

Testing

# Run all tests
pytest

# Run with coverage
pytest --cov=rec_praxis_rlm --cov-report=html

# Run specific test suites
pytest tests/unit/           # Unit tests
pytest tests/integration/    # Integration tests

# Run performance tests
pytest tests/unit/test_memory.py -k "performance"

Current test coverage: 99.38% (327 passing tests)

Security

Sandboxed Code Execution

The SafeExecutor provides multiple layers of security:

  1. AST Validation: Blocks imports, eval, exec, file I/O, network access
  2. Restricted Builtins: Only safe functions allowed (configurable)
  3. Execution Timeout: Prevents infinite loops
  4. Output Limiting: Prevents memory exhaustion
  5. Code Hashing: Audit trail for all executed code

Blocked operations:

  • All imports (import, from ... import)
  • Dangerous builtins (eval, exec, __import__, compile, open)
  • File system access
  • Network access
  • Privileged attributes (__class__, __globals__, __dict__)

ReDoS Protection

The DocumentSearcher validates regex patterns to prevent Regular Expression Denial of Service attacks:

  • Pattern length limits (<500 chars)
  • Nested quantifier detection ((a+)+)
  • Excessive wildcard detection (>3 instances of .* or .+)
  • Overlapping alternation warnings

Advanced Features

Async Support

import asyncio
from rec_praxis_rlm.memory import ProceduralMemory
from rec_praxis_rlm.rlm import RLMContext

async def main():
    memory = ProceduralMemory(config)
    context = RLMContext(config)

    # Async memory recall
    experiences = await memory.arecall(
        env_features=["python"],
        goal="debug error"
    )

    # Async code execution
    result = await context.asafe_exec("sum(range(1000000))")

asyncio.run(main())

Custom Embedding Providers

from rec_praxis_rlm.embeddings import APIEmbedding
from rec_praxis_rlm.memory import ProceduralMemory

# Use OpenAI embeddings
embedding_provider = APIEmbedding(
    api_provider="openai",
    api_key="sk-...",
    model_name="text-embedding-3-small"
)

memory = ProceduralMemory(
    config,
    embedding_provider=embedding_provider
)

Memory Maintenance

# Compact memory (remove old/low-value experiences)
memory.compact(max_size=1000, min_similarity=0.7)

# Recompute embeddings (after changing embedding model)
new_provider = SentenceTransformerEmbedding("new-model")
memory.recompute_embeddings(new_provider)

Custom Metrics

from rec_praxis_rlm.metrics import memory_retrieval_quality, SemanticF1Score

# Memory retrieval quality metric
score = memory_retrieval_quality(
    example={"env_features": [...], "goal": "...", "expected_success_rate": 0.8},
    prediction=retrieved_experiences
)

# Semantic F1 scoring for DSPy optimization
f1_metric = SemanticF1Score(relevance_threshold=0.7)
score = f1_metric(example, prediction)

MLflow Integration

from rec_praxis_rlm.telemetry import setup_mlflow_tracing

# Enable automatic MLflow tracing
setup_mlflow_tracing(experiment_name="my-agent-experiment")

# All DSPy operations are now traced automatically
planner = PraxisRLMPlanner(memory, config)
result = planner.plan(goal="...", env_features=[...])

# View traces in MLflow UI
# mlflow ui --port 5000

Examples

See the examples/ directory for complete examples:

  • quickstart.py - Basic memory and context usage
  • log_analyzer.py - Log analysis with RLM context
  • web_agent.py - Web scraping agent with procedural memory
  • optimization.py - DSPy MIPROv2 optimizer usage

Contributing

Contributions welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE for details.

Citation

If you use rec-praxis-rlm in your research, please cite:

@software{rec_praxis_rlm,
  title = {rec-praxis-rlm: Procedural Memory and REPL Context for Autonomous Agents},
  author = {Your Name},
  year = {2025},
  url = {https://github.com/your-org/rec-praxis-rlm}
}

Acknowledgments

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rec_praxis_rlm-0.2.0.tar.gz (52.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rec_praxis_rlm-0.2.0-py3-none-any.whl (37.6 kB view details)

Uploaded Python 3

File details

Details for the file rec_praxis_rlm-0.2.0.tar.gz.

File metadata

  • Download URL: rec_praxis_rlm-0.2.0.tar.gz
  • Upload date:
  • Size: 52.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.14

File hashes

Hashes for rec_praxis_rlm-0.2.0.tar.gz
Algorithm Hash digest
SHA256 ce19a0a6ff253cb2dce987345657bbf8cdb0bb6088d8c5cf71bd10c006a71561
MD5 f71f0bd242532db98f02907cf7a67cff
BLAKE2b-256 da14352a42f7af46ba5f35a53fab0ad587450a55cba9e52dd96e7f8df812b203

See more details on using hashes here.

File details

Details for the file rec_praxis_rlm-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: rec_praxis_rlm-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 37.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.14

File hashes

Hashes for rec_praxis_rlm-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 579a59e5726398202a0a814f6580ab2508f5190475957ce69bd020b9aac3142c
MD5 4ac03581c17274749a5945e3c0603051
BLAKE2b-256 dec69fffbfd6ee3f51ec7e7a4be66bfaecdaef03526ea7f3ad13a744dcf488ba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page