# reasoning_bank


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Overview

The ReasoningBank provides **ontology-specific procedural recipes** that
guide the LLM in domain-specific ontology exploration tasks.

### Architecture: Memory vs Recipes

**IMPORTANT ARCHITECTURAL DECISION (2026-01-19 Refactor):**

This module was refactored to align with the ReasoningBank paper’s
memory-based learning model:

- **General strategies** (universal patterns): →
  `procedural_memory.bootstrap_general_strategies()` (LEARNED)
- **Ontology-specific patterns** (PROV, SIO, etc.): →
  `reasoning_bank.ONTOLOGY_RECIPES` (AUTHORED)

**Rationale:** - General strategies are LEARNED from experience and
stored as MemoryItems (BM25-retrieved) - Ontology-specific patterns are
AUTHORED by domain experts and stored as Recipes (always injected) -
This separation enables: learning new strategies over time while
maintaining domain-specific guidance

### Four-Layer Context Injection

1.  **Layer 0: Sense Card** - Compact ontology metadata (always
    injected)
2.  **Layer 1: Retrieved Memories** - General strategies from
    procedural_memory (BM25-retrieved)
3.  **Layer 2: Ontology Recipes** - Domain-specific patterns (this
    module)
4.  **Layer 3: Base Context** - GraphMeta summary

### Design Principles

- **Explicit procedures**: Step-by-step tool usage patterns
- **Grounded in tools**: Only reference available functions
- **Expected iterations**: Set clear convergence expectations
- **Domain-specific**: Recipes capture ontology-specific conventions
  (e.g., PROV Activity-Entity patterns)

## Imports

## Recipe Schema

------------------------------------------------------------------------

### Recipe

``` python

def Recipe(
    id:str, title:str, when_to_use:str, procedure:str, expected_iterations:int, layer:int, task_types:list,
    ontology:Optional=None
)->None:

```

*A procedural recipe for ontology exploration.*

Recipes provide explicit step-by-step guidance on HOW to use ontology
exploration tools to accomplish specific tasks.

## Ontology-Specific Recipes (Layer 2)

**After 2026-01-19 Refactor:** This section now contains ONLY
ontology-specific recipes.

**What moved:** Universal patterns (describe entity, find subclasses,
etc.) moved to `procedural_memory.bootstrap_general_strategies()`.

**What stays:** Ontology-specific patterns like: - PROV: Activity-Entity
relationship patterns - SIO: Measurement and process patterns  
- Domain-specific conventions and idioms

**Current status:** Placeholder (ONTOLOGY_RECIPES = \[\]) - to be
populated with domain-specific recipes as needed.

``` python
# Test Recipe creation
test_recipe = CORE_RECIPES[1]  # recipe-1-describe-entity
print(f"Recipe: {test_recipe.title}")
print(f"Layer: {test_recipe.layer}")
print(f"Expected iterations: {test_recipe.expected_iterations}")
print(f"Task types: {test_recipe.task_types}")
print(f"\nFormatted:")
print(test_recipe.format_for_injection())
```

## Recipe Retrieval Functions

------------------------------------------------------------------------

### format_recipes_for_injection

``` python

def format_recipes_for_injection(
    recipes:list
)->str:

```

*Format recipes as markdown for context injection.*

Args: recipes: List of Recipe objects

Returns: Formatted markdown string

------------------------------------------------------------------------

### retrieve_task_recipes

``` python

def retrieve_task_recipes(
    task_type:str, k:int=2
)->list:

```

*Retrieve task-type specific recipes.*

Args: task_type: Task type from classify_task_type() k: Number of
recipes to retrieve

Returns: List of relevant Recipe objects

------------------------------------------------------------------------

### get_core_recipes

``` python

def get_core_recipes(
    limit:int=2
)->list:

```

*Get always-injected core recipes.*

Args: limit: Maximum number of core recipes to return

Returns: List of core Recipe objects

------------------------------------------------------------------------

### classify_task_type

``` python

def classify_task_type(
    query:str
)->str:

```

*Classify query into task type for recipe selection.*

Args: query: User query string

Returns: Task type: ‘entity_discovery’, ‘entity_description’,
‘hierarchy’, ‘property_discovery’, ‘pattern_search’,
‘relationship_discovery’

``` python
# Test recipe retrieval
print("Test 1: Classify task types")
queries = [
    "What is Activity?",
    "Find all subclasses of Activity",
    "What properties have Entity as domain?",
    "How are Activity and Entity related?"
]

for q in queries:
    task_type = classify_task_type(q)
    print(f"  '{q}' → {task_type}")

print("\nTest 2: Get core recipes")
core = get_core_recipes(limit=2)
print(f"  Retrieved {len(core)} core recipes:")
for r in core:
    print(f"    - {r.title}")

print("\nTest 3: Retrieve task-specific recipes")
task_recipes = retrieve_task_recipes('hierarchy', k=2)
print(f"  Retrieved {len(task_recipes)} recipes for 'hierarchy':")
for r in task_recipes:
    print(f"    - {r.title}")

print("\nTest 4: Format recipes")
formatted = format_recipes_for_injection(core[:1])
print(f"  Formatted length: {len(formatted)} chars")
print(f"\nFormatted output (first 300 chars):")
print(formatted[:300] + "...")
```

## Context Injection

Four-layer context injection strategy: 1. **Layer 0:** Sense card (from
structured sense) 2. **Layer 1:** Core recipes (always injected) 3.
**Layer 2:** Task-type recipes (query-dependent) 4. **Layer 3:**
Ontology-specific knowledge (future)

------------------------------------------------------------------------

### inject_context

``` python

def inject_context(
    query:str, base_context:str, sense:dict=None, memory_store:NoneType=None, ontology:str=None, max_memories:int=3,
    max_task_recipes:int=2
)->str:

```

*Build complete context with sense + memories + recipes.*

Injection order: 1. Sense card (Layer 0) - if provided 2. Retrieved
memories (Layer 1) - general strategies from memory_store 3. Task-type
recipes (Layer 2) - ontology-specific patterns 4. Base context -
original graph summary

Args: query: User query base_context: Base context string (e.g.,
GraphMeta.summary()) sense: Structured sense document (from
build_sense_structured) memory_store: MemoryStore with general
strategies ontology: Optional ontology name for ontology-specific
recipes max_memories: Maximum memories to retrieve max_task_recipes:
Maximum task-type recipes to inject

Returns: Enhanced context string

## Enhanced RLM Runner

------------------------------------------------------------------------

### rlm_run_enhanced

``` python

def rlm_run_enhanced(
    query:str, context:str, ns:dict=None, sense:dict=None, memory_store:NoneType=None, ontology:str=None,
    kwargs:VAR_KEYWORD
)->tuple:

```

*RLM run with sense and memory injection.*

This is a drop-in replacement for rlm_run() that automatically enhances
context with: - Layer 0: Structured sense card - Layer 1: Retrieved
procedural memories (general strategies) - Layer 2: Ontology-specific
recipes

Args: query: User query context: Base context (e.g.,
GraphMeta.summary()) ns: Namespace dict sense: Structured sense document
(from build_sense_structured) memory_store: MemoryStore with general
strategies ontology: Optional ontology name \*\*kwargs: Additional
arguments passed to rlm_run()

Returns: (answer, iterations, final_ns) - same as rlm_run()

## Tests

``` python
# Test inject_context with memory_store
from rlm.procedural_memory import MemoryStore, bootstrap_general_strategies

print("Test: inject_context() with memory_store")
print("=" * 70)

# Create memory store with general strategies
memory_store = MemoryStore()
strategies = bootstrap_general_strategies()
for s in strategies:
    memory_store.add(s)

print(f"Memory store: {len(memory_store.memories)} strategies")

# Simulate a sense document
test_sense = {
    'sense_card': {
        'ontology_id': 'test',
        'domain_scope': 'Test ontology',
        'triple_count': 100,
        'class_count': 10,
        'property_count': 5,
        'key_classes': [],
        'key_properties': [],
        'label_predicates': ['rdfs:label'],
        'description_predicates': ['rdfs:comment'],
        'available_indexes': {},
        'quick_hints': ['Test hint'],
        'uri_pattern': 'http://test.org/'
    },
    'sense_brief': {}
}

query = "What is Activity?"
base_context = "Test base context"

enhanced = inject_context(
    query=query,
    base_context=base_context,
    sense=test_sense,
    memory_store=memory_store,
    max_memories=2
)

print(f"\nQuery: '{query}'")
print(f"\nEnhanced context length: {len(enhanced)} chars")
print(f"\nContext structure:")
if '# Ontology:' in enhanced:
    print("  ✓ Layer 0: Sense card")
if 'Relevant Prior Experience' in enhanced or 'Describe Entity' in enhanced:
    print("  ✓ Layer 1: Retrieved memories (general strategies)")
if 'Base Context' in enhanced:
    print("  ✓ Base context included")

print(f"\nFirst 400 chars of enhanced context:")
print("-" * 70)
print(enhanced[:400] + "...")
```

    Test: inject_context() with memory_store
    ======================================================================
    Memory store: 7 strategies

    Query: 'What is Activity?'

    Enhanced context length: 1003 chars

    Context structure:
      ✓ Layer 0: Sense card
      ✓ Layer 1: Retrieved memories (general strategies)
      ✓ Base context included

    First 400 chars of enhanced context:
    ----------------------------------------------------------------------
    # Ontology: test

    **Domain**: Test ontology

    **Stats**: 100 triples, 10 classes, 5 properties

    **Key Classes**:

    **Key Properties**:

    **Labels via**: rdfs:label

    **Quick Hints**:
    - Test hint

    ## Relevant Prior Experience

    Before taking action, briefly assess which of these strategies apply to your current task and which do not.

    ### 1. Describe Entity by Label
    Universal pattern for finding and des...

## Validation

Validate memory-recipe separation and ensure correct architecture.

------------------------------------------------------------------------

### validate_memory_recipe_separation

``` python

def validate_memory_recipe_separation(
    memory_store
)->dict:

```

*Ensure general strategies aren’t duplicated in ONTOLOGY_RECIPES.*

Validates: - No title overlap between universal memories and ontology
recipes - All ONTOLOGY_RECIPES have ontology field set (domain-specific)

Args: memory_store: MemoryStore (typically with bootstrap strategies)

Returns: Dictionary with validation results

``` python
# Test memory-recipe separation validation
from rlm.procedural_memory import MemoryStore, bootstrap_general_strategies

print("Test: validate_memory_recipe_separation()")
print("=" * 60)

memory_store = MemoryStore()
for s in bootstrap_general_strategies():
    memory_store.add(s)

result = validate_memory_recipe_separation(memory_store)
print(f"Valid: {result['valid']}")
print(f"Overlap count: {result['overlap_count']}")
print(f"Ontology recipes count: {result['ontology_recipes_count']}")
print(f"All recipes have ontology field: {result['all_recipes_have_ontology']}")

if result['valid']:
    print("\n✓ Memory-recipe separation validated successfully")
else:
    print(f"\n✗ Validation failed: {result['overlapping_titles']}")
```

    Test: validate_memory_recipe_separation()
    ============================================================
    Valid: True
    Overlap count: 0
    Ontology recipes count: 0
    All recipes have ontology field: True

    ✓ Memory-recipe separation validated successfully
